1. 程式人生 > >【魯班學院】面試總結:Java高階篇(上):集合的型別以及重新認識HashMap

【魯班學院】面試總結:Java高階篇(上):集合的型別以及重新認識HashMap

1.你用過哪些集合類?

    大公司最喜歡問的Java集合類面試題
    40個Java集合面試問題和答案
    java.util.Collections 是一個包裝類。它包含有各種有關集合操作的靜態多型方法。
    java.util.Collection 是一個集合介面。它提供了對集合物件進行基本操作的通用介面方法。 

    Collection
     ├List
    │├LinkedList
    │├ArrayList
    │└Vector
    │ └Stack
    └Set
    Map    
    ├Hashtable
    ├HashMap  
    └WeakHashMap    

> ArrayList、HashMap、TreeMap和HashTable類提供對元素的隨機訪問。

(1)執行緒安全

    Vector
    HashTable(不允許插空值)

(2)非執行緒安全


ArrayList
LinkedList
HashMap(允許插入空值)
HashSet
TreeSet
TreeMap(基於紅黑樹的Map實現)

2.你說說 arraylist 和 linkedlist 的區別?ArrayList和LinkedList兩者都實現了List介面,但是它們之間有些不同。

 1、ArrayList是由Array所支援的基於一個索引的資料結構,所以它提供對元素的隨機訪問。
 2、與ArrayList相比,在LinkedList中插入、新增和刪除一個元素會更快。
 3、LinkedList比ArrayList消耗更多的記憶體,因為LinkedList中的每個節點儲存了前後節點的引用。

 3.HashMap 底層是怎麼實現的?還有什麼處理雜湊衝突的方法?處理雜湊衝突的方法:
解決HashMap一般沒有什麼特別好的方式,要不擴容重新hash要不優化衝突的連結串列結構。

1.開放定地址法-線性探測法
2.開放定地址法-平方探查法
3.連結串列解決-可以用紅黑樹提高查詢效率

 


HashMap簡介: HashMap 是一個散列表,它儲存的內容是鍵值對(key-value)對映。 HashMap
繼承於AbstractMap,實現了Map、Cloneable、java.io.Serializable介面。 HashMap
的實現不是同步的,這意味著它不是執行緒安全的,但可以用
 Collections的synchronizedMap方法使HashMap具有執行緒安全的能力。它的key、value都可以為null。此外,HashMap中的對映不是有序的。

**HashMap 的例項有兩個引數影響其效能:“初始容量” 和 “載入因子”。**

初始容量預設是16。預設載入因子是 0.75,這是在時間和空間成本上尋求一種折衷。載入因子過高雖然減少了空間開銷,但同時也增加了查詢成本。HashMap是陣列+連結串列+紅黑樹(JDK1.8增加了紅黑樹部分)實現的,當連結串列長度太長(預設超過8)時,連結串列就轉換為紅黑樹。

 4.Java8系列之重新認識HashMap

功能實現-方法:
1、確定雜湊桶陣列索引位置 :這裡的Hash演算法本質上就是三步:取key的hashCode值、高位運算、取模運算。

方法一:static final int hash(Object key) { //jdk1.8 & jdk1.7int h;// h = key.hashCode() 為第一步 取hashCode值// h ^ (h >>> 16) 為第二步 高位參與運算return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);}

方法二:static int indexFor(int h, int length) { //jdk1.7的原始碼,jdk1.8沒有這個方法,但是實現原理一樣的return h & (length-1); //第三步 取模運算}

**1.分析HashMap的put方法
   2.擴容機制:原來的兩倍**

 5.熟悉什麼演算法,還有說說他們的時間複雜度?

 經典排序演算法總結與實現

6.ArrayList和Vector的底層程式碼和他們的增長策略,它們是如何進行擴容的?

ArrayList 預設陣列大小是10,其中ensureCapacity擴容,trimToSize容量調整到適中,擴充套件後陣列大小為((原陣列長度1.5)與傳遞引數中較大者。

Vector的擴容,是可以指定擴容因子,同時Vector擴容策略是:1.原來容量的2倍,2.原來容量+擴容引數值。(*詳細內容可以配合閱讀原始碼)

7.jvm 原理,程式執行區域劃分

 問:Java執行時資料區域? 回答:包括程式計數器、JVM棧、本地方法棧、方法區、堆。 問:方法區裡存放什麼?
本地方法棧:和jvm棧所發揮的作用類似,區別是jvm棧為jvm執行java方法(位元組碼)服務,而本地方法棧為jvm使用的native方法服務。
JVM棧:區域性變量表、運算元棧、動態連結、方法出口。 方法區:用於儲存已被虛擬機器載入的類資訊,常量、靜態變數、即時編譯器編譯後的程式碼等。
堆:存放物件例項。

 8.minor GC 與 Full GC,分別什麼時候會觸發? 分別採用哪種垃圾回收演算法?簡單介紹演算法。

GC(或Minor GC):收集 生命週期短的區域(Young area)。
Full GC (或Major GC):收集生命週期短的區域(Young area)和生命週期比較長的區域(Old area)對整個堆進行垃圾收集。

新生代通常存活時間較短基於Copying演算法進行回收,將可用記憶體分為大小相等的兩塊,每次只使用其中一塊;當這一塊用完了,就將還活著的物件複製到另一塊上,然後把已使用過的記憶體清理掉。在HotSpot裡,考慮到大部分物件存活時間很短將記憶體分為Eden和兩塊Survivor,預設比例為8:1:1。代價是存在部分記憶體空間浪費,適合在新生代使用。

老年代與新生代不同,老年代物件存活的時間比較長、比較穩定,因此採用標記(Mark)演算法來進行回收,所謂標記就是掃描出存活的物件,然後再進行回收未被標記的物件,回收後對用空出的空間要麼進行合併、要麼標記出來便於下次進行分配,總之目的就是要減少記憶體碎片帶來的效率損耗。
在執行機制上JVM提供了序列GC(Serial MSC)、並行GC(Parallel MSC)和併發GC(CMS)。

Minor GC ,Full GC 觸發條件
Minor GC觸發條件:當Eden區滿時,觸發Minor GC。

Full GC觸發條件:

1、呼叫System.gc時,系統建議執行Full GC,但是不必然執行。
2、老年代空間不足。
3、方法去空間不足。
4、通過Minor GC後進入老年代的平均大小大於老年代的可用記憶體。
5、由Eden區、From Space區向To Space區複製時,物件大小大於To Space可用記憶體,則把該物件轉存到老年代,且老年代的可用記憶體小於該物件大小。

 9.HashMap 實現原理

在java程式語言中,最基本的結構就是兩種,一個是陣列,另外一個是模擬指標(引用),所有的資料結構都可以用這兩個基本結構來構造的,HashMap也不例外。HashMap實際上是一個“連結串列雜湊”的資料結構,即陣列和連結串列的結合體。

 10.java.util.concurrent 包下使用過哪些

    (1).阻塞佇列
    BlockingQueue

( ArrayBlockingQueue, DelayQueue, LinkedBlockingQueue,SynchronousQueue,LinkedTransferQueue,LinkedBlockingDeque)
    (2).ConcurrentHashMap
    (3).Semaphore–訊號量
    (4) .CountDownLatch–閉鎖
    (5).CyclicBarrier–柵欄
    (6).Exchanger–交換機
    (7).Executor-
    >ThreadPoolExecutor,ScheduledThreadPoolExecutor

    Semaphore semaphore = new Semaphore(1);//critical section semaphore.acquire();...semaphore.release(); 

9.鎖

 Lock–ReentrantLock,ReadWriteLock,Condition,LockSupport


      Lock lock = new ReentrantLock();lock.lock();//critical section lock.unlock();

10.concurrentMap 和 HashMap 區別

1.hashMap可以有null的鍵,concurrentMap不可以有
2.hashMap是執行緒不安全的,在多執行緒的時候需要Collections.synchronizedMap(hashMap),ConcurrentMap使用了重入鎖保證執行緒安全。
3.在刪除元素時候,兩者的演算法不一樣。 ConcurrentHashMap和Hashtable主要區別就是圍繞著鎖的粒度以及如何鎖,可以簡單理解成把一個大的HashTable分解成多個,形成了鎖分離。

11.訊號量是什麼,怎麼使用?volatile關鍵字是什麼?

訊號量-semaphore:荷蘭著名的電腦科學家Dijkstra 於1965年提出的一個同步機制。是在多執行緒環境下使用的一種設施,它負責協調各個執行緒,以保證它們能夠正確、合理的使用公共資源。

 整形訊號量:表示共享資源狀態,且只能由特殊的原子操作改變整型量。
 同步與互斥:同類程序為互斥關係(印表機問題),不同程序為同步關係(消費者生產者)。
 
 使用volatile關鍵字是解決同步問題的一種有效手段。 java
 volatile關鍵字預示著這個變數始終是“儲存進入了主存”。更精確的表述就是每一次讀一個volatile變數,都會   從主存讀取,而不是CPU的快取。同樣的道理,每次寫一個volatile變數,都是寫回主存,而不僅僅是CPU的緩     存。
 Java 保證volatile關鍵字保證變數的改變對各個執行緒是可見的。

13.阻塞隊列了解嗎?怎麼使用?

 阻塞佇列 (BlockingQueue)是Javautil.concurrent包下重要的資料結構,BlockingQueue提供了執行緒安全的佇列訪問方式:當阻塞佇列進行插入資料時,如果佇列已滿,執行緒將會阻塞等待直到佇列非滿;從阻塞佇列取資料時,如果佇列已空,執行緒將會阻塞等待直到佇列非空。併發包下很多高階同步類的實現都是基於BlockingQueue實現的。

以ArrayBlockingQueue為例,我們先來看看程式碼:

    public void put(E e) throws InterruptedException {if (e == null) throw new
    NullPointerException();final ReentrantLock lock = this.lock;lock.lockInterruptibly();try
    {while (count == items.length)notFull.await();enqueue(e);} finally {lock.unlock();}}

從put方法的實現可以看出,它先獲取了鎖,並且獲取的是可中斷鎖,然後判斷當前元素個數是否等於陣列的長度,如果相等,則呼叫notFull.await()進行等待,當被其他執行緒喚醒時,通過enqueue(e)方法插入元素,最後解鎖。

    /*** Inserts element at current put position, advances, and signals.* Call only when
    holding lock.*/private void enqueue(E x) {// assert lock.getHoldCount() == 1;// assert items[putIndex] == null;final Object[]
     items = this.items;items[putIndex] = x;if 
     (++putIndex == items.length) putIndex = 0;count++;notEmpty.signal();}

插入成功後,通過notEmpty喚醒正在等待取元素的執行緒。

 13.Java中的NIO,BIO,AIO分別是什麼?

IO的方式通常分為幾種,同步阻塞的BIO、同步非阻塞的NIO、非同步非阻塞的AIO`

1.BIO,同步阻塞式IO,簡單理解:一個連線一個執行緒.BIO方式適用於連線數目比較小且固定的架構,這種方式對伺服器資源要求比較高,併發侷限於應用中,JDK1.4以前的唯一選擇,但程式直觀簡單易理解。

在JDK1.4之前,用Java編寫網路請求,都是建立一個ServerSocket,然後,客戶端建立Socket時
就會詢問是否有執行緒可以處理,如果沒有,要麼等待,要麼被拒絕。即:一個連線,要求Server 對應一個處理執行緒。

2.NIO,同步非阻塞IO,簡單理解:一個請求一個執行緒.NIO方式適用於連線數目多且連線比較短(輕操作)的架構,比如聊天伺服器,併發侷限於應用中,程式設計比較複雜,JDK1.4開始支援。

 NIO本身是基於事件驅動思想來完成的,其主要想解決的是BIO的大併發問題:
 在使用同步I/O的網路應用中,如果要同時處理多個客戶端請求,或是在客戶端要同時和多個伺服器進行通訊,就必須使用多執行緒來處理。也就是說,將每一個客戶端請求分配給一個執行緒來單獨處理。這樣做雖然可以達到我們的要求,但同時又會帶來另外一個問題。
 由於每建立一個執行緒,就要為這個執行緒分配一定的記憶體空間(也叫工作儲存器),而且作業系統本身也對執行緒的總數有一定的限制。如果客戶端的請求過多,服務端程式可能會因為不堪重負而拒絕客戶端的請求,甚至伺服器可能會因此而癱瘓。

3.AIO,非同步非阻塞IO,簡單理解:一個有效請求一個執行緒.AIO方式使用於連線數目多且連線比較長(重操作)的架構,比如相簿伺服器,充分呼叫OS參與併發操作,程式設計比較複雜,JDK7開始支援。

 14.類載入機制是怎樣的?

JVM中類的裝載是由ClassLoader和它的子類來實現的,Java
ClassLoader是一個重要的Java執行時系統元件。它負責在執行時查詢和裝入類檔案的類。
類載入的五個過程:載入、驗證、準備、解析、初始化。`

從類被載入到虛擬機器記憶體中開始,到卸御出記憶體為止,它的整個生命週期分為7個階段,載入(Loading)、驗證(Verification)、準備(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)、卸御(Unloading)。其中驗證、準備、解析三個部分統稱為連線。

15.什麼是冪等性?
所謂冪等,簡單地說,就是對介面的多次呼叫所產生的結果和呼叫一次是一致的。
那麼我們為什麼需要介面具有冪等性呢?設想一下以下情形:

•在App中下訂單的時候,點選確認之後,沒反應,就又點選了幾次。在這種情況下,如果無法保證該介面的冪等性,那麼將會出現重複下單問題。

•在接收訊息的時候,訊息推送重複。如果處理訊息的介面無法保證冪等,那麼重複消費訊息產生的影響可能會非常大。

16.有哪些 JVM 調優經驗?

Jvm引數總結:http://linfengying.com/?p=2470

◾記憶體引數

 

上面有7中收集器,分為兩塊,上面為新生代收集器,下面是老年代收集器。如果兩個收集器之間存在連線,就說明它們可以搭配使用。

17.分散式 CAP 瞭解嗎?

一致性(Consistency) 
 可用性(Availability) 
 分割槽容忍性(Partition tolerance)

 18.ava中HashMap的key值要是為類物件則該類需要滿足什麼條件?

需要同時重寫該類的hashCode()方法和它的equals()方法。

當程式試圖將一個 key-value 對放入 HashMap 中時,程式首先根據該 key 的 hashCode() 返回值決定該
 Entry 的儲存位置:
 如果兩個 Entry 的 key 的 hashCode() 返回值相同,那它們的儲存位置相同。
 如果這兩個 Entry 的 key 通過 equals 比較返回 true,新新增 Entry 的 value 將覆蓋集合中原有 Entry
 的 value,但 key 不會覆蓋。
 如果這兩個 Entry 的 key 通過 equals 比較返回 false,新新增的 Entry 將與集合中原有 Entry 形成
 Entry 鏈,而且新新增的 Entry 位於 Entry 鏈的頭部——具體說明繼續看 addEntry() 方法的說明。

 19Java 垃圾回收會出現不可回收的物件嗎?怎麼解決記憶體洩露問題?怎麼定位問題源?
一般不會有不可回收的物件,因為現在的GC會回收不可達記憶體。

 20.終止執行緒有幾種方式?終止執行緒標記變數為什麼是 valotile 型別?

1.執行緒正常執行完畢,正常結束    

2.監視某些條件,結束執行緒的不間斷執行

 3.使用interrupt方法終止執行緒

在定義exit時,使用了一個Java關鍵字volatile,這個關鍵字的目的是使exit同步,也就是說在同一時刻只能由一個執行緒來修改exit的值。

21.用過哪些併發的資料結構? cyclicBarrier 什麼功能?訊號量作用?資料庫讀寫阻塞怎麼解決?

•主要有鎖機制,然後基於CAS的concurrent包。 •CyclicBarrier的字面意思是可迴圈使用(Cyclic)的屏障(Barrier)。它要做的事情是,讓一組執行緒到達一個屏障(也可以叫同步點)時被阻塞,直到最後一個執行緒到達屏障時,屏障才會開門,所有被屏障攔截的執行緒才會繼續幹活。
CyclicBarrier預設的構造方法是CyclicBarrier(int
parties),其引數表示屏障攔截的執行緒數量,每個執行緒呼叫await方法告訴CyclicBarrier我已經到達了屏障,然後當前執行緒被阻塞。
•CountDownLatch的計數器只能使用一次。而CyclicBarrier的計數器可以使用reset() 方法重置。
•Semaphore(訊號量)是用來控制同時訪問特定資源的執行緒數量,它通過協調各個執行緒,以保證合理的使用公共資源。
很多年以來,我都覺得從字面上很難理解Semaphore所表達的含義,只能把它比作是控制流量的紅綠燈,比如XX馬路要限制流量,只允許同時有一百輛車在這條路上行使,其他的都必須在路口等待,所以前一百輛車會看到綠燈,可以開進這條馬路,後面的車會看到紅燈,不能駛入XX馬路,但是如果前一百輛中有五輛車已經離開了XX馬路,那麼後面就允許有5輛車駛入馬路。

 這個例子裡說的車就是執行緒,駛入馬路就表示執行緒在執行,離開馬路就表示執行緒執行完成,看見紅燈就表示執行緒被阻塞,不能執