程序員:爲何「基礎不牢」成爲我薪資被砍的理由?!

前言

我發現有不少程序員面試前都是準備地好好的,什麼疑難雜症,未解之謎都是準備得妥妥的,張口就來。反而到了最容易的Javajava

基礎的時候,各類翻車(多是以爲基礎的內容太簡單沒有花精力),原本是可以拿到更高的薪資,就由於基礎沒有回答好,被程序員

抓住當成藉口又砍了好幾K,實在是得不償失。因此今天給你們分享一份Java基礎的面試題彙總以及解析,以便你們更好地應對面試

面試,衝擊更高薪資!算法

1. String類爲何是final的

主要是爲了」安全性「和」效率「的緣故,由於:數組

一、因爲String類不能被繼承,因此就不會沒修改,這就避免了由於繼承引發的安全隱患;緩存

二、String類在程序中出現的頻率比較高,若是爲了不安全隱患,在它每次出現時都用final來修飾,這無疑會下降程序的執行效安全

率,因此乾脆直接將其設爲final一提升效率;服務器

2. HashMap的源碼,實現原理,底層結構。

HashMap就是數組+鏈表的組合實現,每一個數組元素存儲一個鏈表的頭結點,本質上來講是哈希表「拉鍊法」的實現。數據結構

HashMap的鏈表元素對應的是一個靜態內部類Entry,Entry主要包含key,value,next三個元素多線程

主要有put和get方法,put的原理是,經過hash%Entry.length計算index,此時記做Entry[index]=該元素。若是index相同

就是新入的元素放置到Entry[index],原先的元素記做Entry[index].next

get就比較簡單了,先遍歷數組,再遍歷鏈表元素。

null key老是放在Entry數組的第一個元素

解決hash衝突的方法:鏈地址法

再散列rehash的過程:肯定容量超過目前哈希表的容量,從新調整table 的容量大小,當超過容量的最大值時,取

Integer.Maxvalue

3. 什麼是Java集合類?說說你知道的幾個Java集合類。

集合類存放於java.util包中。

集合類存放的都是對象的引用,而非對象自己,出於表達上的便利,咱們稱集合中的對象就是指集合中對象的引用(reference)。

集合類型主要有3種:set(集)、list(列表)和map(映射)。

集合接口分爲:Collection和Map,list、set實現了Collection接口

4. 描述一下ArrayList和LinkedList各自實現和區別

ArrayList,LinkedList都實現了java.util.List接口,

  • ArrayList是實現了基於動態數組的數據結構,LinkedList基於鏈表的數據結構。
  • 對於隨機訪問get和set,ArrayList以爲優於LinkedList,由於LinkedList要移動指針。
  • 對於新增和刪除操做add和remove,LinedList比較佔優點,由於ArrayList要移動數據。

5. Java中的隊列都有哪些,有什麼區別

Java中的隊列都有哪些,其實是問queue的實現有哪些,如:ConcurrentLinkedQueue、LinkedBlockingQueue 、

ArrayBlockingQueue、LinkedList。

關於ConcurrentLinkedQueue和LinkedBlockingQueue:

  • LinkedBlockingQueue是使用鎖機制,ConcurrentLinkedQueue是使用CAS算法,雖然LinkedBlockingQueue的底層獲取鎖也是使用的CAS算法
  • 關於取元素,ConcurrentLinkedQueue不支持阻塞去取元素,LinkedBlockingQueue支持阻塞的take()方法,如若你們須要ConcurrentLinkedQueue的消費者產生阻塞效果,須要自行實現
  • 關於插入元素的性能,從字面上和代碼簡單的分析來看ConcurrentLinkedQueue確定是最快的,可是這個也要看具體的測試場景,我作了兩個簡單的demo作測試,測試的結果以下,兩個的性能差很少,但在實際的使用過程當中,尤爲在多cpu的服務器上,有鎖和無鎖的差距便體現出來了,ConcurrentLinkedQueue會比LinkedBlockingQueue快不少:ConcurrentLinkedQueuePerform:在使用ConcurrentLinkedQueue的狀況下100個線程循環增長的元素數爲:33828193 
    LinkedBlockingQueuePerform:在使用LinkedBlockingQueue的狀況下100個線程循環增長的元素數爲:33827382

6. 反射中,Class.forName和classloader的區別

Java中Class.forName和classloader均可以用來對類進行加載。

Class.forName除了將類的.class文件加載到jvm中以外,還會對類進行解釋,執行類中的static塊。

而classloader只幹一件事情,就是將.class文件加載到jvm中,不會執行static中的內容,只有在newInstance纔會去執行static塊。

Class.forName(name,initialize,loader)帶參數也可控制是否加載static塊。而且只有調用了newInstance()方法採用調用構造函數,建立類的對象。

7. Java七、Java8的新特性(baidu問的,好BT)

如下特性爲我的比較關注的特性,並不齊全;想了解更多,請自行搜索官方文檔。

Java7特性:

1.switch case可使用String,原來只能用int和char;
2.支持2進制0b開頭;支持數字中間有下劃線,解析時自動剔除;
3.一次抓多個異常;用|隔開;
4.try-with-resource,在try中打開資源,系統自動在使用完後關閉;
5. Map<String, List<String>> anagrams = new HashMap<>(); 對抗Google的guava.
6.集合類能夠像js中的數組同樣賦值和引用了。
List<String> list = ["item"];       
    String item = list[0];         
    Set<String> set = {"item"};              
    Map<String, Integer> map = {"key" : 1};       

    int value = map["key"];    

7. 把字符串常量池從permgen區移到了堆區;致使String.intern()方法在1.7以前和以後表現出現不一致;

Java8特性:
1.lambda表達式;
2.新增stream,Date,Time,Base64工具類;
3.使用metaspace,元空間替代permgen區;
4.類依賴分析器:jdeps,能夠以包,目錄,文件夾做爲輸入,輸出依賴關係,沒有的會顯示 not found
5.jjs,能夠執行JavaScript代碼;

8. Java數組和鏈表兩種結構的操做效率,在哪些狀況下,哪些操做的效率高

數組在隨機訪問數據、隨機增長數據、隨機刪除數據的執行效率上比鏈表的效率高,數據量越小,二者之間效率的差距越小,數據量越大差距越大。

也歡迎你們一塊兒討論面試終於到的各類奇葩問題,特意建了一個Java技術交流羣:895244712,但願有個小圈子的朋友能夠加進來,不定時分享一些技術乾貨,但願能帶來幫助。

9. Java內存泄露的問題調查定位:jmap,jstack的使用等等

詳細解析:https://blog.csdn.net/sinat_29581293/article/details/70214436

10. string、stringbuilder、stringbuffer區別

這三個類之間的區別主要是在兩個方面,即運行速度和線程安全這兩方面。

  1. 首先說運行速度,或者說是執行速度,在這方面運行速度快慢爲:StringBuilder > StringBuffer > String

  String最慢的緣由:

  String爲字符串常量,而StringBuilder和StringBuffer均爲字符串變量,即String對象一旦建立以後該對象是不可更改的,但後二者的對象是變量,是能夠更改的。

2. 再來講線程安全

  在線程安全上,StringBuilder是線程不安全的,而StringBuffer是線程安全的

  若是一個StringBuffer對象在字符串緩衝區被多個線程使用時,StringBuffer中不少方法能夠帶有synchronized關鍵字,因此能夠保證線程是安全的,但StringBuilder的方法則沒有該關鍵字,因此不能保證線程安全,有可能會出現一些錯誤的操做。因此若是要進行的操做是多線程的,那麼就要使用StringBuffer,可是在單線程的狀況下,仍是建議使用速度比較快的StringBuilder。

  3. 總結一下
  String:適用於少許的字符串操做的狀況

  StringBuilder:適用於單線程下在字符緩衝區進行大量操做的狀況

  StringBuffer:適用多線程下在字符緩衝區進行大量操做的狀況

11.hashtable和hashmap的區別

1. 存儲結構

HashMap

HashTable

數組 + 鏈表/紅黑樹

數組 + 鏈表

 

 

 

HashMap的存儲規則:

優先使用數組存儲, 若是出現Hash衝突, 將在數組的該位置拉伸出鏈表進行存儲(在鏈表的尾部進行添加), 若是鏈表的長度大於設定值後, 將鏈表轉爲紅黑樹.

HashTable的存儲規則:

優先使用數組存儲, 存儲元素時, 先取出下標上的元素(可能爲null), 而後添加到數組元素Entry對象的next屬性中(在鏈表的頭部進行添加).

出現Hash衝突時, 新元素next屬性會指向衝突的元素. 若是沒有Hash衝突, 則新元素的next屬性就是null

描述的有點模糊, 貼出源碼會清晰一點:

Entry<K,V> e = (Entry<K,V>) tab[index];
tab[index] = new Entry<>(hash, key, value, e);

2. 擴容方式

HashMap

HashTable

oldCap * 2

oldCap * 2 + 1

 

 

 

3. 關於null值

HashMap

HashTable

key, value 都可覺得 null

key, value 均能夠爲 null

 

 

 

4. 線程安全

HashMap HashTable
線程不安全 線程安全

 

 

 

13 .異常的結構,運行時異常和非運行時異常

大神的解釋:https://blog.csdn.net/qq_27093465/article/details/52268531

14. String a= 「abc」 String b = 「abc」 String c = new String(「abc」) String d = 「ab」 + 「c」 .他們之間用 == 比較的結果

傳送門:http://www.javashuo.com/article/p-aryreled-a.html

15. String 類的經常使用方法

String類中提供了大量的操做方法,這裏例舉13種關於String類經常使用的方法供你們參考。參考代碼以下:
package cn.mc;
public class StringTestMc {
 private String str = "helloWorld";
 /**
  * 將字符串變成一個字符數組
  */
 public void tocharyArry() {
  char c[] = str.toCharArray();
  for (int i = 0; i < c.length; i++) {
   System.out.println("轉爲數組輸出:" + c[i]);
  }
 }
 /**
  * 從字符串中取出指定位置的字符
  */
 public void tocharAt() {
  char c = str.charAt(3);
  System.out.println("指定字符爲:" + c);
 }
 /**
  * 將字符串變成一個byte數組
  */
 public void tobyte() {
  byte b[] = str.getBytes();
  System.out.println("轉換成byte數組輸出爲:" + new String(b));
 }
 /**
  * 取得一個字符串的長度
  */
 public void tolength() {
  int l = str.length();
  System.out.println("這個字符串的長度爲:" + l);
 }
 /**
  * 查找一個指定的字符串是否存在,返回的是字符串的位置,若是不存在,則返回-1
  */
 public void toindexOf() {
  int a1 = str.indexOf("e");// 查找字符e的位置
  int a2 = str.indexOf("l", 2);// 查找l的位置,從第3個開始查找
  System.out.println("e的位置爲:" + a1);
  System.out.println("l的位置爲:" + a2);
 }
 /**
  * 去掉字符串左右空格
  */
 public void totrim() {
  String str1 = "       hello         ";
  System.out.println("去掉左右空格後輸出:" + str1.trim());
 }
 /**
  * 字符串的截取
  */
 public void tosubstring() {
  System.out.println("截取後的字符爲:" + str.substring(0, 3));// 截取0-3個位置的內容
  System.out.println("從第3個位置開始截取:" + str.substring(2));// 從第3個位置開始截取
 }
 /**
  * 按照指定的字符串拆分字符,拆分的數據將以字符串數組的形式返回
  */
 public void tosplit() {
  String s[] = str.split("e");// 按hello中的e進行字符串拆分
  for (int i = 0; i < s.length; i++) {
   System.out.println("拆分後結果爲:" + s[i]);
  }
 }
 /**
  * 將字符串進行大小寫轉換
  */
 public void tochange() {
  System.out.println("將\"hello\"轉換成大寫爲:" + str.toUpperCase());// 將hello轉換成大寫
  System.out.println("將\"HELLO\"轉換成大寫爲:"
    + str.toUpperCase().toLowerCase());// 將HELLO轉換成小寫
 }
 /**
  * 判斷是否以指定的字符串開頭或者結尾
  */
 public void tostartsWithOrendWith()
 {
  if(str.startsWith("he"))//判斷字符串是否以he開頭
  {
   System.out.println("字符串是以he開頭");
  }
  if(str.endsWith("lo"))
  {
   System.out.println("字符串是以lo結尾");
  } 
 }
 /**
  * 兩個String類型內容比較
  */
 public void toequals()
 {
  String str3="world";
  if(str.equals(str3))
  {
   System.out.println("這倆個String類型的值相等");
  }
  else
   System.out.println("這倆個String類型的不值相等");
 }
 /**
  * 兩個字符串不區分大小寫進行比較
  */
 public void toequalslgnoreCase()
 {
  String str4="HELLO";
  if(str.equalsIgnoreCase(str4))
  {
   System.out.println("hello和HELLO忽略大小寫比較值相等");
  }
 }
 /**
  * 將一個指定獲得字符串替換成其餘字符串
  */
 public void toreplaceAll()
 {
  String str5=str.replaceAll("l", "a");
  System.out.println("替換後的結果爲:"+str5);
 }
 public static void main(String[] args) {
 StringTest obj = new StringTest();
  obj.tocharyArry();
  obj.tocharAt();
  obj.tobyte();
  obj.tolength();
  obj.toindexOf();
  obj.totrim();
  obj.tosubstring();
  obj.tosplit();
  obj.tochange();
  obj.tostartsWithOrendWith();
  obj.toequals();
  obj.toequalslgnoreCase();
  obj.toreplaceAll();
 }
}

16. Java 的引用類型有哪幾種

有這樣一類對象:當內存空間還足夠,則可保留在內存中;若是內存空間在gc以後仍是很是緊張,則可拋棄這些對象。不少系統的緩存功能適合這樣的場景,因此jdk1.2之後

java將引用分爲了強引用、軟引用、弱引用、虛引用四種,引用強度一次減弱。

  • 強引用:相似Object a=new Object()這類,永遠不會被回收。
  • 軟引用:SoftReference,當系統快要發生內存溢出異常時,將會把這些對象列入回收範圍進行二次回收,若是此次回收仍是沒有足夠內存,則拋出內存溢出異常。
  • 弱引用:比軟引用更弱,活不過下一次gc。不管當前內存是否足夠,下一次gc都會被回收掉。
  • 虛引用:又叫幻引用,最弱,一個對象時候有虛引用的存在,不會對它的生存時間構成影響,惟一目的就是能在這對象被回收之後收到一個系統通知。。

17. 抽象類和接口的區別

接口是公開的,裏面不能有私有的方法或變量,是用於讓別人使用的,而抽象類是能夠有私有方法或私有變量的,

另外,實現接口的必定要實現接口裏定義的全部方法,而實現抽象類能夠有選擇地重寫須要用到的方法,通常的應用裏,最頂級的是接口,而後是抽象類實現接口,最後纔到具體類實現。

還有,接口能夠實現多重繼承,而一個類只能繼承一個超類,但能夠經過繼承多個接口實現多重繼承,接口還有標識(裏面沒有任何方法,如Remote接口)和數據共享(裏面的變量全是常量)的做用.

18. java的基礎類型和字節大小

java數據類型 字節 表示範圍

byte(字節型) 1 -128~127
boolean(布爾型) 1 true或false
short(短整型) 2 -32768~32767
char(字符型) 2 從字符型對應的整型數來劃分,其表示範圍是0~65535
int(整型) 4 -2147483648~2147483647
float(浮點型) 4 -3.4E38~3.4E38
double(雙精度型) 8 -1.7E308~1.7E308
long(長整型) 8 -9223372036854775808 ~ 9223372036854775807

19. Hashtable,HashMap,ConcurrentHashMap 底層實現原理與線程安全問題

大神又來了:https://blog.csdn.net/qq_27093465/article/details/52279473

21. Hash衝突怎麼辦?哪些解決散列衝突的方法?

Hash算法解決衝突的方法通常有如下幾種經常使用的解決方法 
1, 開放定址法: 
所謂的開放定址法就是一旦發生了衝突,就去尋找下一個空的散列地址,只要散列表足夠大,空的散列地址總能找到,並將記錄存入 
公式爲:fi(key) = (f(key)+di) MOD m (di=1,2,3,……,m-1) 
※ 用開放定址法解決衝突的作法是:當衝突發生時,使用某種探測技術在散列表中造成一個探測序列。沿此序列逐個單元地查找,直到找到給定的關鍵字,或者 
碰到一個開放的地址(即該地址單元爲空)爲止(若要插入,在探查到開放的地址,則可將待插入的新結點存人該地址單元)。查找時探測到開放的地址則代表表 
中無待查的關鍵字,即查找失敗。 
好比說,咱們的關鍵字集合爲{12,67,56,16,25,37,22,29,15,47,48,34},表長爲12。 咱們用散列函數f(key) = key mod l2 
當計算前S個數{12,67,56,16,25}時,都是沒有衝突的散列地址,直接存入: 
這裏寫圖片描述 
計算key = 37時,發現f(37) = 1,此時就與25所在的位置衝突。 
因而咱們應用上面的公式f(37) = (f(37)+1) mod 12 = 2。因而將37存入下標爲2的位置: 
這裏寫圖片描述

2, 再哈希法: 
再哈希法又叫雙哈希法,有多個不一樣的Hash函數,當發生衝突時,使用第二個,第三個,….,等哈希函數
計算地址,直到無衝突。雖然不易發生彙集,可是增長了計算時間。

3, 鏈地址法: 
鏈地址法的基本思想是:每一個哈希表節點都有一個next指針,多個哈希表節點能夠用next指針構成一個單向鏈表,被分配到同一個索引上的多個節點能夠用這個單向 
鏈表鏈接起來,如: 
鍵值對k2, v2與鍵值對k1, v1經過計算後的索引值都爲2,這時及產生衝突,可是能夠通道next指針將k2, k1所在的節點鏈接起來,這樣就解決了哈希的衝突問題 
這裏寫圖片描述
4, 創建公共溢出區: 
這種方法的基本思想是:將哈希表分爲基本表和溢出表兩部分,凡是和基本表發生衝突的元素,一概填入溢出表

22. hashCode() 與 equals() 生成算法、方法怎麼重寫

參考地址:https://blog.csdn.net/neosmith/article/details/17068365

結語

好了,今天的分享就到這裏了,但願可以幫助到須要面試的道友順利渡劫。高深的問題當然要好好回答,但基礎也不能落下,顧

此失彼致使薪資被砍相信也不是你們但願看到的,反正我是經歷過,很難受,哈哈。

相關文章
相關標籤/搜索