-
1 # 山東中公
-
2 # JAVA破局之路
一、String 原理,String 、StringBuffer、StringBuilder區別。
String是final類,屬於不可變字串,採用char陣列。
StringBuffer是執行緒安全的,內部採用synchronized。
StringBuilder是非執行緒安全的。
二、String與StringBuilder拼接字串哪個效能好,為什麼?
StringBuilder效能比較好,String在拼接的時候會new出多個物件,消耗資源。尤其是在for迴圈下進行拼接效能差距很明顯。
三、介面與抽象類的區別
1. 介面的方法預設是 public,所有方法在介面中不能有實現(Java 8 開始介面方法可以有預設實現),抽象類可以有非抽象的方法
2. 介面中的例項變數預設是 final 型別的,而抽象類中則不一定
3. 一個類可以實現多個介面,但最多隻能實現一個抽象類
4. 一個類實現介面的話要實現介面的所有方法,而抽象類不一定
5. 介面不能用 new 例項化,但可以宣告,但是必須引用一個實現該介面的物件 從設計面來說,抽象是對類的抽象,是一種模板設計,介面是行為的抽象,是一種行為的規範。
四、過載與重寫的區別
過載(Overload)是讓類以統一的方式處理不同型別資料的一種手段,實質表現就是多個具有不同的引數個數或者型別的同名函式(返回值型別可隨意,不能以返回型別作為過載函式的區分標準)同時存在於同一個類中,是一個類中多型性的一種表現(呼叫方法時透過傳遞不同引數個數和引數型別來決定具體使用哪個方法的多型性)。
重寫(Override)是父類與子類之間的多型性,實質是對父類的函式進行重新定義,如果在子類中定義某方法與其父類有相同的名稱和引數則該方法被重寫,不過子類函式的訪問修飾許可權不能小於父類的;若子類中的方法與父類中的某一方法具有相同的方法名、返回型別和引數表,則新方法將覆蓋原有的方法,如需父類中原有的方法則可使用 super 關鍵字。
五、陣列與連結串列的區別
六、介紹一下ArrayList
1、ArrayList底層資料結構是一個數組,陣列元素型別為Object,對ArrayList的所有操作都是基於陣列。
2、ArrayList不是執行緒安全的。對ArrayList進行新增元素的操作的時候是分兩個步驟進行的,即第一步先在object[size]的位置上存放需要新增的元素;第二步將size的值增加1。由於這個過程在多執行緒的環境下是不能保證具有原子性的,因此ArrayList在多執行緒的環境下是執行緒不安全的。
如果非要在多執行緒的環境下使用ArrayList,就需要保證它的執行緒安全性,通常有兩種解決辦法:第一,使用synchronized關鍵字;第二,可以用Collections類中的靜態方法synchronizedList();
3、ArrayList預設大小為10
4、ArrayList擴容機制:
第一,在add()方法中呼叫ensureCapacityInternal(size + 1)方法來確定集合確保新增元素成功的最小集合容量minCapacity的值。引數為size+1,代表的含義是如果集合新增元素成功後,集合中的實際元素個數。換句話說,集合為了確保新增元素成功,那麼集合的最小容量minCapacity應該是size+1。在ensureCapacityInternal方法中,首先判斷elementData是否為預設的空陣列,如果是,minCapacity為minCapacity與集合預設容量大小中的較大值。
第二,呼叫ensureExplicitCapacity(minCapacity)方法來確定集合為了確保新增元素成功是否需要對現有的元素陣列進行擴容。首先將結構性修改計數器加一;然後判斷minCapacity與當前元素陣列的長度的大小,如果minCapacity比當前元素陣列的長度的大小大的時候需要擴容,進入第三階段。
第三,如果需要對現有的元素陣列進行擴容,則呼叫grow(minCapacity)方法,引數minCapacity表示集合為了確保新增元素成功的最小容量。在擴容的時候,首先將原元素陣列的長度增大1.5倍(oldCapacity + (oldCapacity >> 1)),然後對擴容後的容量與minCapacity進行比較:① 新容量小於minCapacity,則將新容量設為minCapacity;②新容量大於minCapacity,則指定新容量。最後將舊陣列複製到擴容後的新陣列中。
for迴圈遍歷不可以,會報ConcurrentModificationException異常,迭代器Iterator下可以。
內部有一個modCount 進行修改次數檢查。
如果沒checkForComodification去檢查expectedModCount與modCount相等,這個程式肯定會報ArrayIndexOutOfBoundsException
八、LinkedList底層資料結構是什麼?說明ArrayList,LinkedList二者區別?
1.ArrayList是實現了基於動態陣列的資料結構,LinkedList基於連結串列的資料結構每個元素都包含了 上一個和下一個元素的引用,所以add/remove 只會影響到上一個和下一個元素,。
2.對於隨機訪問get和set,ArrayList覺得優於LinkedList,因為LinkedList要移動指標。
九、簡單介紹一下HashMap?
1、負載因子0.75 , 提高空間利用率和 減少查詢成本的折中,主要是泊松分佈,0.75的話碰撞最小。
2、擾動函式就是解決碰撞問題,減少碰撞。
3、hasMap的容量儘量是2的倍數,這樣使雜湊均勻,不易出現hash衝突
HashMap預設初始化大小16,資料結構是一個數組+連結串列+紅黑樹(平衡二叉樹紅黑節點)。
Put的時候首先拿到hash值看是否存在值如果沒有值直接放入,存在則進行比較是否相等,不等生成連結串列,當連結串列大於8的時候生成紅黑樹。
HashMap是執行緒不安全的。
十、介紹一下ConcurrentHashMap
concurrentHashMap是一個執行緒安全的高可用HashMap。
1.8拋棄了之前的segement分段上鎖,採用了CAS+synchronized來保證併發安全,並且吧put的流程更加細化,而且resize的時候不會阻塞任何一個執行緒。
重要引數:
MIN_TRANSFER_STRIDE: 意思是resize時候每個執行緒每次最小的搬運量(搬運多少個entry),範圍會繼續細分以便可以允許多個resize執行緒。
RESIZE_STAMP_BITS :位的個數來用來生成戳,用在sizeCtrl裡面;
MAX_RESIZERS:最大參與resize的執行緒數量;
RESIZE_STAMP_SHIFT:用來記錄在sizeCtrl中size戳的位偏移數。
Put主邏輯:
1、首先判斷key\value都不能為null
2、進行自旋操作,每次把當前的table賦給tab
3、計算key的hash
4、如果當前table沒有初始化,現代用initTable方法將tab初始化。
5、Tab索引i的位置元素為null,則直接使用CAS插入
6、判斷是否在resize(擴容),在擴容走helpTransfer - transfer
7、沒有resize走正常put
8、用synchronized針對單個節點加鎖
9、判斷節點hash(正常node大於0,樹為-2)
10、正常節點插入,插入到隊尾
11、樹節點插入
initTable方法
1、自旋操作每次針對tab賦值而且判斷長度
2、如果搶鎖失敗(sizeCtl作為自旋鎖使用),則告訴cpu讓出時間片(Thread.yield())
3、搶鎖成功,再次檢測tab的賦值以及陣列長度
4、SizeCtl置為n的0.75
5、finally裡面邏輯,sizeCtl賦值並解鎖
addCount方法
增加表容量的計數,如果這個表需要resize但還沒開始resize,則初始化transfer(這個東西用來進行resize)。如果已經開始resize了,則看看需不需要加入幫助一起resize。然後重新檢查表的計數看看需不需要再次resize
transfer方法(resize用此方法):
原理就是讓每一個put完的執行緒,或者想要put的執行緒到了整個表需要resize的時候都過來進入resize流水線工作,直到有一個執行緒說自己已經全部弄完了,方法才能返回。
以前的正常設計是resize的時候整個表就阻塞住了,但是現在resize的時候,想要操作的執行緒都會來參與一起resize,這麼一來其他的執行緒就不用幹等著了。
參考文件:https://www.cnblogs.com/kobebyrant/p/11296309.html
自旋鎖:
自旋鎖?它是為實現保護共享資源而提出一種鎖機制。其實,自旋鎖與互斥鎖比較類似,它們都是為了解決對某項資源的互斥使用。無論是互斥鎖,還是自旋鎖,在任何時刻,最多隻能有一個保持者,也就說,在任何時刻最多隻能有一個執行單元獲得鎖。但是兩者在排程機制上略有不同。對於互斥鎖,如果資源已經被佔用,資源申請者只能進入睡眠狀態。但是自旋鎖不會引起呼叫者睡眠,如果自旋鎖已經被別的執行單元保持,呼叫者就一直迴圈在那裡看是否該自旋鎖的保持者已經釋放了鎖,"自旋"一詞就是因此而得名。
十一、比較各種集合
HashMap與TreeMap:
1、都是非執行緒安全
2、HashMap透過hashCode進行快速查詢,無序;treeMap有序。
3、hashMap基於雜湊實現,treeMap基於紅黑樹實現
5、HashMap比TreeMap快一點,建議使用hashMap,需要排序的時候再用treeMap。
HashSet與ArrayList:
1.HashSet
1) HashSet不能夠儲存相同的元素,元素是否相同的判斷:重寫元素的equals方法。equals方法和hashCode方法必須相容,如:equals方法判斷的是使用者的名字name,那麼hashCode的返回的hashcode必須是name。hashcode();
2) HashSet儲存是無序的,儲存的順序與新增的順序是不一致的,它不是線性結構,而是雜湊結構,(透過散列表:雜湊單元指向連結串列)。因此,HashSet的查詢效率相對比較高。
3) HashSet不是執行緒安全的,不是執行緒同步的。這需要自己實現執行緒同步:Collections.synchronizedCollection(),方法實現。
4) Haset底層用了HashMap用key做的HashSet的value,迭代器迴圈程式碼:map.keySet().iterator()
2.ArrayList
1) ArrayList中存放順序和新增順序是一致的。並且可重複元素。
2) 不是執行緒安全的,不是執行緒同步的。
3) ArrayList是透過可變大小的陣列實現的,允許null在內的所有元素。
4) ArrayList適合透過位子來讀取元素。
回覆列表
【真題】假如你是某單位的公職人員,你的親戚和朋友經常來向你打聽單位內部的事,有事讓你說關係幫忙,你該如何處理?
【真題】愛狗協會人士舉報說堵截了一輛拉了200只狗的汽車,但是汽車司機的老婆以死相逼,你怎麼看?
【真題】近一段時間,網路上出現了很多抨擊劉胡蘭、邱少雲、狼牙山五壯士等一些中國抗日英雄的言論,對此,你怎麼看?
【真題】近年來有很多放生積德行為,但是最近有人放生老鼠,你怎麼看?