2020年5月面試JAVA基礎整理含Java8新特性

Java基礎部分:
Java集合中List,Set以及Map

引用:

https://blog.csdn.net/zhangqunshuai/article/details/80660974

  • List , Set, Map都是接口,前兩個繼承至Collection接口,Map爲獨立接口
  • Set下有HashSet,LinkedHashSet,TreeSet
  • List下有ArrayList,Vector,LinkedList
  • Map下有Hashtable,LinkedHashMap,HashMap,TreeMap
  • Collection接口下還有個Queue接口,有PriorityQueue類

在這裏插入圖片描述

注意:
Queue接口與List、Set同一級別,都是繼承了Collection接口。
看圖你會發現,LinkedList既可以實現Queue接口,也可以實現List接口.只不過呢, LinkedList實現了Queue接口。Queue接口窄化了對LinkedList的方法的訪問權限(即在方法中的參數類型如果是Queue時,就完全只能訪問Queue接口所定義的方法 了,而不能直接訪問 LinkedList的非Queue的方法),以使得只有恰當的方法纔可以使用。

SortedSet是個接口,它裏面的(只有TreeSet這一個實現可用)中的元素一定是有序的。

總結:
Collection接口:
— List 有序,可重複

  • ArrayList

優點: 底層數據結構是數組,查詢快,增刪慢。
缺點: 線程不安全,效率高

  • Vector

優點: 底層數據結構是數組,查詢快,增刪慢。
缺點: 線程安全,效率低

  • LinkedList

優點: 底層數據結構是鏈表,查詢慢,增刪快。
缺點: 線程不安全,效率高
—Set 無序,唯一

  • HashSet

底層數據結構是哈希表。(無序,唯一)
如何來保證元素唯一性?
1.依賴兩個方法:hashCode()和equals()

  • LinkedHashSet

底層數據結構是鏈表和哈希表。(FIFO插入有序,唯一)
1.由鏈表保證元素有序
2.由哈希表保證元素唯一

  • TreeSet

底層數據結構是紅黑樹。(唯一,有序)
1.如何保證元素排序的呢?
自然排序
比較器排序
2.如何保證元素唯一性的呢?
根據比較的返回值是否是0來決定

/** Collection集合
Set 可以保證 唯一
TreeSet 和LinkedHashSet 是有序的
HashSet 是無序的
**/
/**
List 
線程安全:
Vector
線程不安全:
ArrayList 和 LinkedList

查詢多:ArrayList
增刪多:LinkedList
**/

Map 接口:

在這裏插入圖片描述

Map接口有三個比較重要的實現類,分別是HashMap、TreeMap和HashTable。

  • TreeMap是有序的,HashMap和HashTable是無序的。
  • Hashtable的方法是同步的,HashMap的方法不是同步的。這是兩者最主要的區別。
  • HashMap效率較高,Hashtable效率較低。 如果對同步性或與遺留代碼的兼容性沒有任何要求,建議使用HashMap。
    查看Hashtable的源代碼就可以發現,除構造函數外,Hashtable的所有 public 方法聲明中都有
    synchronized關鍵字,而HashMap的源碼中則沒有。
  • Hashtable不允許null值,HashMap允許null值(key和value都允許)
  • 父類不同:Hashtable的父類是Dictionary,HashMap的父類是AbstractMap

**

重點問題重點分析:

**
(一).TreeSet, LinkedHashSet and HashSet 的區別

TreeSet, LinkedHashSet and HashSet 在java中都是實現Set的數據結構
  • TreeSet的主要功能用於排序
  • LinkedHashSet的主要功能用於保證FIFO即有序的集合(先進先出)
  • HashSet只是通用的存儲數據的集合

2. 相同點

  • Duplicates elements: 因爲三者都實現Set interface,所以三者都不包含duplicate elements
  • Thread safety: 三者都不是線程安全的,如果要使用線程安全可以Collections.synchronizedSet()

3. 不同點

  • Performance and Speed:
    HashSet插入數據最快,其次LinkHashSet,最慢的是TreeSet因爲內部實現排序

**

Hashmap的結構,1.7和1.8區別

**

https://blog.csdn.net/qq_36520235/article/details/82417949

Hashmap的結構,1.7和1.8有哪些區別
不同點:

(1)JDK1.7用的是頭插法,而JDK1.8及之後使用的都是尾插法,那麼他們爲什麼要這樣做呢?因爲JDK1.7是用單鏈表進行的縱向延伸,當採用頭插法時會容易出現逆序且環形鏈表死循環問題。但是在JDK1.8之後是因爲加入了紅黑樹使用尾插法,能夠避免出現逆序且鏈表死循環的問題。

(2)擴容後數據存儲位置的計算方式也不一樣:1. 在JDK1.7的時候是直接用hash值和需要擴容的二進制數進行&(這裏就是爲什麼擴容的時候爲啥一定必須是2的多少次冪的原因所在,因爲如果只有2的n次冪的情況時最後一位二進制數才一定是1,這樣能最大程度減少hash碰撞)(hash值 & length-1)

圖解補充頭插法和尾插法:

頭插法:

在頭節點的後面進行插入操作,後一個插入進來的值,在前一個插入進來的值與頭節點之間。:將新形成的節點的下一個賦值爲header再把新形成的節點地址傳給header即將header向前移動
在這裏插入圖片描述

尾插法:

設法找到插入結點的上一個結點,總而言之,尾插法就是要使後面插入的結點在前一個插入結點和NULL值之間。
在這裏插入圖片描述

引用:

https://blog.csdn.net/jankin6/article/details/80954203

HashMap桶中鏈表轉紅黑樹爲什麼選擇數字8?

翻譯過來大概的意思是:理想情況下使用隨機的哈希碼,容器中節點分佈在hash桶中的頻率遵循泊松分佈(具體可以查看http://en.wikipedia.org/wiki/Poisson_distribution),按照泊松分佈的計算公式計算出了桶中元素個數和概率的對照表,可以看到鏈表中元素個數爲8時的概率已經非常小,再多的就更少了,所以原作者在選擇鏈表元素個數時選擇了8,是根據概率統計而選擇的。

//Java中解釋的原因
   * Because TreeNodes are about twice the size of regular nodes, we
     * use them only when bins contain enough nodes to warrant use
     * (see TREEIFY_THRESHOLD). And when they become too small (due to
     * removal or resizing) they are converted back to plain bins.  In
     * usages with well-distributed user hashCodes, tree bins are
     * rarely used.  Ideally, under random hashCodes, the frequency of
     * nodes in bins follows a Poisson distribution
     * (http://en.wikipedia.org/wiki/Poisson_distribution) with a
     * parameter of about 0.5 on average for the default resizing
     * threshold of 0.75, although with a large variance because of
     * resizing granularity. Ignoring variance, the expected
     * occurrences of list size k are (exp(-0.5) * pow(0.5, k) /
     * factorial(k)). The first values are:
     *
     * 0:    0.60653066
     * 1:    0.30326533
     * 2:    0.07581633
     * 3:    0.01263606
     * 4:    0.00157952
     * 5:    0.00015795
     * 6:    0.00001316
     * 7:    0.00000094
     * 8:    0.00000006
     * more: less than 1 in ten million

1.8之後HashMap變爲先插入後擴容的原因

在JDK1.7中的話,是先進行擴容後進行插入的,就是當你發現你插入的桶是不是爲空,如果不爲空說明存在值就發生了hash衝突,那麼就必須得擴容,但是如果不發生Hash衝突的話,說明當前桶是空的(後面並沒有掛有鏈表),那就等到下一次發生Hash衝突的時候在進行擴容,但是當如果以後都沒有發生hash衝突產生,那麼就不會進行擴容了,減少了一次無用擴容,也減少了內存的使用

hashMap在jdk1.7與jdk1.8中的原理及不同

https://blog.csdn.net/changhangshi/article/details/82114727

hashMap爲何採用hash表存數據。如果不用hash表,集合中數據是無序的,當我們向集合中添加一個數據時需要同集合中所有的數據進行equals比較,當集合數據比較大時效率是非常的低。因此用hash表存儲數據效率非常高。hash表的底層是數組,數組中存的是entry對象,默認長度是16.
當我們往hash表中添加一個對象時,會調用對象的hash code方法,根據hash算法算出對應的數組的索引值,再根據索引值查找數組,數組中是否存在對象,如果不存在對象直接存進去。 如果存在對象,則通過equals比較兩個對象的key值是否相等,如果相等則覆蓋value值。

如果不相等則形成鏈表結構,jdk1.7後加的在前面,先加的移下,這種情況叫碰撞。這種碰撞的情況應儘量避免,否存一個索引中鏈表的數據大量時,該索引當再次插入一個對象時equals比較全部影響效率。這時我們將equals和hashcode方法重寫的嚴謹點,這種還是避免不了,因爲數組的索引值有限。因此hashMap提供了加載因子避免碰撞,默認0.75,當元素到達現有的hash表的75%時擴容。一旦擴充就會重新排序hash表,減少碰撞概率。

https://blog.csdn.net/qiaoqiao0609/article/details/79082860

簡單回顧ConcurrentHashMap在jdk1.7中的設計

  • 與Hashtable不同的是,ConcurrentHashMap使用的是分段鎖技術,將ConcurrentHashMap容器的數據分段存儲,每一段數據分配一個Segment,當線程佔用一個Segment時,其他線程可以訪問其他段的數據.(每個segment都是一個鎖).
    與hashtable相比,這麼設計的目的是對於put,
    remove等操作,可以減少併發衝突,對不屬於同一個片段的節點可以併發操作,大大提高了性能.

Segment : 可重入鎖(在JAVA環境下 ReentrantLock 和synchronized 都是 可重入鎖),繼承ReentrantLock, 也稱之爲桶( 本質上Segment類就是一個小的hashmap,裏面table數組存儲了各個節點的數據,繼承了ReentrantLock, 可以作爲互斥鎖使用 ) 每個Segment守護着一個HashEntry數組裏的元素,當對HashEntry數組的數據進行修改時,必須首先獲得它對應的Segment鎖。

HashEntry : 主要存儲鍵值對, 這裏也可以叫節點

ConcurrentHashMap包含一個Segment數組,每個Segment包含一個HashEntry數組,當修改HashEntry數組,採用開鏈法處理衝突,所以它的每個HashEntry元素又是鏈表結構的元素。

ConcurrentHashMap在jdk1.8中做了兩方面的改進

**改進一:**取消segments字段,直接採用transient volatile HashEntry<K,V>[] table保存數據,採用table數組元素作爲鎖,從而實現了對每一行數據進行加鎖,進一步減少併發衝突的概率。

**改進二:**將原先table數組+單向鏈表的數據結構,變更爲table數組+單向鏈表+紅黑樹的結構。對於hash表來說,最核心的能力在於將key hash之後能均勻的分佈在數組中。如果hash之後散列的很均勻,那麼table數組中的每個隊列長度主要爲0或者1。但實際情況並非總是如此理想,雖然ConcurrentHashMap類默認的加載因子爲0.75,但是在數據量過大或者運氣不佳的情況下,還是會存在一些隊列長度過長的情況,如果還是採用單向列表方式,那麼查詢某個節點的時間複雜度爲O(n);因此,對於個數超過8(默認值)的列表,jdk1.8中採用了紅黑樹的結構,那麼查詢的時間複雜度可以降低到O(logN),以此改進性能。

鎖相關:

https://www.jianshu.com/p/d4e339d595bb

互斥鎖:
互斥量(mutex)是阻塞鎖,當某線程無法獲取鎖時,該線程會被直接掛起,該線程不再消耗CPU時間,當其他線程釋放鎖後,操作系統會激活那個被掛起的線程,讓其投入運行。
當使用synchroinzed鎖住多段不同的代碼片段,但是這些同步塊使用的同步監視器對象是同一個時,那麼這些代碼片段之間就是互斥的。多個線程不能同時執行他們。
舉例子:
比如去銀行辦業務,你需要取號,然後去等待區等待,此時你就是一個等待線程,而窗口前正在辦業務的就是正在執行的線程,而窗口就是共享資源,同一時間只能有一條線程使用共享資源,你們是互斥的

自旋鎖:
自旋鎖(spin lock)是一種非阻塞鎖,也就是說,如果某線程需要獲取鎖,但該鎖已經被其他線程佔用時,該線程不會被掛起,而是在不斷的消耗CPU的時間,不停的試圖獲取鎖。
自旋鎖是計算機科學用於多線程同步的一種鎖,線程反覆檢查鎖變量是否可用。由於線程在這一過程中保持執行,因此是一種忙等待。
自旋鎖避免了進程上下文的調度開銷,因此對於線程只會阻塞很短時間的場合是有效的。因此操作系統的實現在很多地方往往用自旋鎖。
自旋鎖比較適用於鎖使用者保持鎖時間比較短的情況
舉例子:
去銀行取錢,門口有一臺ATM機,你可以直接去ATM前面排隊等待,需要時刻關注你前面還有沒有人,當沒有人了也就輪到你了,這就是自旋

鎖消除:
自旋鎖原理非常簡單,如果持有鎖的線程能在很短時間內釋放鎖資源,那麼那些等待競爭鎖的線程就不需要做內核態和用戶態之間的切換進入阻塞掛起狀態,它們只需要等一等(自旋),等持有鎖的線程釋放鎖後即可立即獲取鎖,這樣就避免用戶線程和內核的切換的消耗。
性能原因,一般JVM會限制自旋等待時間。
自旋鎖一般是樂觀鎖。

優點:在鎖競爭不激烈的情況下,佔用鎖的時間非常短的代碼來說,自旋操作(cpu空轉)的消耗小於線程阻塞掛起的消耗。
缺點:如果鎖競爭激烈,或者持有鎖的線程需要長時間佔用鎖執行同步塊,就不適合自旋鎖,這是CPU空轉的消耗大於線程阻塞的消耗。

舉例子:
還是去銀行取錢,不是任何時候你都需要去取號排隊,當確保沒人和你爭搶窗口的時候,你可以直接坐上去辦理業務,不需要取號,這就是鎖消除,實際情況下何時會做這種優化呢?JIt編輯器會判斷當同步塊所使用的鎖對象只能被一個線程訪問時,會做優化

鎖粗化:

通常情況下,爲了保證多線程間的有效併發,會要求每個線程持有鎖的時間儘可能短,但是大某些情況下,一個程序對同一個鎖不間斷、高頻地請求、同步與釋放,會消耗掉一定的系統資源,因爲鎖的講求、同步與釋放本身會帶來性能損耗,這樣高頻的鎖請求就反而不利於系統性能的優化了,雖然單次同步操作的時間可能很短。鎖粗化就是告訴我們任何事情都有個度,有些情況下我們反而希望把很多次鎖的請求合併成一個請求,以降低短時間內大量鎖請求、同步、釋放帶來的性能損耗。

舉例子:
比如一個傻子去銀行取錢,他取號然後等待取錢,輪到他後取了100塊錢然後繼續去取號,繼續等待輪到後再取100,一直重複了5次,那麼他拿500塊錢的時間就被拖得很長,你會想爲什麼不一次性取500呢,這就是代碼中可能出現的問題,當JIT發現一系列連續的操作都對同一個對象反覆加鎖和解鎖,甚至加鎖操作出現在循環體中的時候,會將加鎖同步的範圍擴散(粗化)到整個操作序列的外部。

Java NIO庫中提供的FileChannel類,文件操作特性的優點。

FileChannel的優點

在文件特定位置進行讀寫操作
將文件一部分直接加載到內存,這樣效率更高
以更快的速度將文件數據從一個通道傳輸到另一個通道
鎖定文件的某一部分來限制其他線程訪問
爲了避免數據丟失,強制立即將更新寫入文件並存儲

FileChannel讀操作
當我們讀取一個大文件時,FileChannel比標準I/O執行得更快。需要注意,雖然FileChannel是Java NIO的一部分,但是FileChannel操作是阻塞的,並且沒有非阻塞模式。

流相關面試整理:

https://blog.csdn.net/qq_37875585/article/details/89385688

在 Java 中數據類型可以分爲兩大類:基本類型和引用類型。

基本類型也稱爲值類型,分別是字符類型 char,布爾類型 boolean以及數值類型 byte、short、int、long、float、double。

引用類型則包括類、接口、數組、枚舉等。

JVM相關:

https://blog.csdn.net/weixin_38896998/article/details/86499993?ops_request_misc=%257B%2522request%255Fid%2522%253A%2522158868150819725247661162%2522%252C%2522scm%2522%253A%252220140713.130102334.app%255Fall.57673%2522%257D&request_id=158868150819725247661162&biz_id=0&utm_medium=distribute.pc_search_result.none-task-blog-2allfirst_rank_v2~rank_v25-12%20%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%E2%80%94%20%E7%89%88%E6%9D%83%E5%A3%B0%E6%98%8E%EF%BC%9A%E6%9C%AC%E6%96%87%E4%B8%BACSDN%E5%8D%9A%E4%B8%BB%E3%80%8C_Libbytian%E3%80%8D%E7%9A%84%E5%8E%9F%E5%88%9B%E6%96%87%E7%AB%A0%EF%BC%8C%E9%81%B5%E5%BE%AACC%204.0%20BY-SA%E7%89%88%E6%9D%83%E5%8D%8F%E8%AE%AE%EF%BC%8C%E8%BD%AC%E8%BD%BD%E8%AF%B7%E9%99%84%E4%B8%8A%E5%8E%9F%E6%96%87%E5%87%BA%E5%A4%84%E9%93%BE%E6%8E%A5%E5%8F%8A%E6%9C%AC%E5%A3%B0%E6%98%8E%E3%80%82%20%E5%8E%9F%E6%96%87%E9%93%BE%E6%8E%A5%EF%BC%9Ahttps://blog.csdn.net/sinat_32867867/article/details/105930709

詳細請轉到原文鏈接
在這裏插入圖片描述

Java 內存模型與內存結構

https://blog.csdn.net/ityard/article/details/101693717?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromBaidu-1

線程池的四種阻塞隊列與四種任務拒絕策略

https://blog.csdn.net/qq_35689573/article/details/87863605?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-4

注意:上文並非原創,爲本人收集整理面試所用,所有引用均附原文鏈接,如侵權請聯繫刪除

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章