天天看點

Java 集合看這一篇就夠了,mybatis面試題2020

Create, Read, Update, and Delete.

那我也把這些 API 分為這四大類:

Java 集合看這一篇就夠了,mybatis面試題2020

下面具體來看:

增:

boolean add(E e); 

           

add() 方法傳入的資料類型必須是 Object,是以當寫入基本資料類型的時候,會做自動裝箱 auto-boxing 和自動拆箱 unboxing。

還有另外一個方法 addAll(),可以把另一個集合裡的元素加到此集合中。

boolean addAll(Collection<? extends E> c); 

           

删:

boolean remove(Object o); 

           

remove()是删除的指定元素。

那和 addAll() 對應的,

自然就有removeAll(),就是把集合 B 中的所有元素都删掉。

boolean removeAll(Collection<?> c); 

           

改:

Collection Interface 裡并沒有直接改元素的操作,反正删和增就可以完成改了嘛!

查:

查下集合中有沒有某個特定的元素:

boolean contains(Object o); 

           

查集合 A 是否包含了集合 B:

boolean containsAll(Collection<?> c); 

           

還有一些對集合整體的操作:

判斷集合是否為空:

boolean isEmpty(); 

           

集合的大小:

int size(); 

           

把集合轉成數組:

Object[] toArray(); 

           

以上就是 Collection 中常用的 API 了。

在接口裡都定義好了,子類不要也得要。

當然子類也會做一些自己的實作,這樣就有了不同的資料結構。

那我們一個個來看。

List

Java 集合看這一篇就夠了,mybatis面試題2020

List 最大的特點就是:有序,可重複。

看官網說的:

An ordered collection (also known as a sequence).
Unlike sets, lists typically allow duplicate elements.

這一下把 Set 的特點也說出來了,和 List 完全相反,Set 是 無序,不重複的。

List 的實作方式有 LinkedList 和 ArrayList 兩種,那面試時最常問的就是這兩個資料結構如何選擇。

對于這類選擇問題:

一是考慮資料結構是否能完成需要的功能;

如果都能完成,二是考慮哪種更高效。

(萬事都是如此啊。)

那具體來看這兩個 classes 的 API 和它們的時間複雜度:

Java 集合看這一篇就夠了,mybatis面試題2020

稍微解釋幾個:

add(E e) 是在尾巴上加元素,雖然 ArrayList 可能會有擴容的情況出現,但是均攤複雜度(amortized time complexity)還是 O(1) 的。

add(int index, E e)是在特定的位置上加元素,LinkedList 需要先找到這個位置,再加上這個元素,雖然單純的「加」這個動作是 O(1) 的,但是要找到這個位置還是 O(n) 的。(這個有的人就認為是 O(1),和面試官解釋清楚就行了,拒絕扛精。

remove(int index)是 remove 這個 index 上的元素,是以

  • ArrayList 找到這個元素的過程是 O(1),但是 remove 之後,後續元素都要往前移動一位,是以均攤複雜度是 O(n);
  • LinkedList 也是要先找到這個 index,這個過程是 O(n) 的,是以整體也是 O(n)。

remove(E e)是 remove 見到的第一個這個元素,那麼

  • ArrayList 要先找到這個元素,這個過程是 O(n),然後移除後還要往前移一位,這個更是 O(n),總的還是 O(n);
  • LinkedList 也是要先找,這個過程是 O(n),然後移走,這個過程是 O(1),總的是 O(n).

那造成時間複雜度的差別的原因是什麼呢?

答:

  • 因為 ArrayList 是用數組來實作的。
  • 而數組和連結清單的最大差別就是數組是可以随機通路的(random access)

這個特點造成了在數組裡可以通過下标用 O(1) 的時間拿到任何位置的數,而連結清單則做不到,隻能從頭開始逐個周遊。

也就是說在「改查」這兩個功能上,因為數組能夠随機通路,是以 ArrayList 的效率高。

那「增删」呢?

如果不考慮找到這個元素的時間,

數組因為實體上的連續性,當要增删元素時,在尾部還好,但是其他地方就會導緻後續元素都要移動,是以效率較低;而連結清單則可以輕松的斷開和下一個元素的連接配接,直接插入新元素或者移除舊元素。

但是呢,實際上你不能不考慮找到元素的時間啊。。。而且如果是在尾部操作,資料量大時 ArrayList 會更快的。

是以說:

1.改查選擇 ArrayList;

2.增删在尾部的選擇 ArrayList;

3.其他情況下,如果時間複雜度一樣,推薦選擇 ArrayList,因為 overhead 更小,或者說記憶體使用更有效率。

Vector

那作為 List 的最後一個知識點,我們來聊一下 Vector。這也是一個年齡暴露帖,用過的都是大佬。

那 Vector 和 ArrayList 一樣,也是繼承自 java.util.AbstractList,底層也是用數組來實作的。

但是現在已經被棄用了,因為…它加了太多的 synchronized!

任何好處都是有代價的,線程安全的成本就是效率低,在某些系統裡很容易成為瓶頸,是以現在大家不再在資料結構的層面加 synchronized,而是把這個任務轉移給我們程式員==

那麼面試常問題:Vector 和 ArrayList 的差別是什麼,隻答出來這個還還不太全面。

來看 stack overflow 上的高票回答:

Java 集合看這一篇就夠了,mybatis面試題2020
一是剛才已經說過的線程安全問題;
二是擴容時擴多少的差別。

這個得看看源碼:

Java 集合看這一篇就夠了,mybatis面試題2020

這是 ArrayList 的擴容實作,這個算術右移操作是把這個數的二進制往右移動一位,最左邊補符号位,但是因為容量沒有負數,是以還是補 0.

那右移一位的效果就是除以 2,那麼定義的新容量就是原容量的 1.5 倍。

不了解這個右移操作符的小夥伴,公衆号内回複「二進制」快複習一下吧~

再來看 Vector 的:

Java 集合看這一篇就夠了,mybatis面試題2020

因為通常 capacityIncrement 我們并不定義,是以預設情況下它是擴容兩倍。