一、集合類結構
Java中的集合包含多種數據結構,如鏈表、隊列、哈希表等。從類的繼承結構來說,可以分為兩大類,一類是繼承自Collection接口,這類集合包含List、Set和Queue等集合類。另一類是繼承自Map接口,這主要包含了哈希表相關的集合類。
1.繼承Collection接口

2.繼承Map接口

二、實現原理
1.List (有序,可重復)
常用的實現List接口的主要有ArrayList、Vector、LinkedList 三個,通過查看jdk底層源碼實現,進行簡單的要點總結:
(1)ArrayList
ArrayList是List使用中最常用的實現類,它的查詢速度快,效率高,但增刪慢,線程不安全。
實現原理:
ArrayList底層實現采用的數據結構是數組,並且數組默認大小為10,所以下面兩種方式是等同的:
List list = new ArrayList(); //沒有指定數組大小,使用默認值(默認大小是10) List list = new ArrayList(10); // 指定數組大小為10,傳如的參數便是數組的大小,傳入為10時,跟默認值相同,所以是等同的
要想清楚的理解上面兩中方式,從ArrayList類的構造器就會豁然開朗:
注:不同的jdk版本實現代碼有所不同, 現以jdk1.8為例(個人感覺 jdk1.6的底層實現寫法更好理解,jdk1.8就比1.6較難懂一些)
// 無參構造器
public ArrayList() { this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA; // DEFAULTCAPACITY_EMPTY_ELEMENTDATA是一個默認大小的空實例 } // 有參構造器,參數為列表的初始容量(由於是通過數組實現的,所以可以理解成數組的大小) public ArrayList(int initialCapacity) { if (initialCapacity > 0) { this.elementData = new Object[initialCapacity]; } else if (initialCapacity == 0) { this.elementData = EMPTY_ELEMENTDATA; } else { throw new IllegalArgumentException("Illegal Capacity: "+initialCapacity); } }
擴容機制:
jdk1.8的擴容算法:newCapacity = oldCapacity + ( oldCapacity >> 1 ) ; // oldCapacity >> 2 移位運算,此處相當於oldCapacity除以2,但是 >> 這種寫法更加高效
jdk1.6的擴容算法:newCapacity = ( oldCapacity * 3 ) / 2 +1 ;
參數介紹:newCapacity 是擴容后的容量大小,oldCapacity 是擴容前的大小
查看jdk源碼,移位運算需要學習下,換句話說,就是需要學習下二進制,比如:反碼、補碼,二進制與十進制、十六進制的相互轉換。與機器交流的都是0110等,所以挺重要的。
(2)Vector
Vector的底層也是通過數組實現的,默認大小也是10。主要特點:查詢快,增刪慢 , 線程安全,但是效率低
實現原理:
創建對象與ArrayList類似,但有一點不同,它可以設置擴容是容量增長大小。
根據Vector的三個構造器就可以很明了的理解 new Vector(); 與 new Vector(10);與 new Vector(10,0); 三個是等同的,很明了就不贅述了。
1.無參構造器
public Vector() { this(10); } 2.傳一個參數(容量大小) 容量大小即底層數組大小 public Vector(int initialCapacity) { this(initialCapacity, 0); }
3.傳兩個參數(容量大小,容量修正) 容量修正即擴容時的增加量 public Vector(int initialCapacity, int capacityIncrement) { super(); if (initialCapacity < 0) throw new IllegalArgumentException("Illegal Capacity: "+ initialCapacity); this.elementData = new Object[initialCapacity]; this.capacityIncrement = capacityIncrement; }
擴容機制:
jdk1.8的擴容算法:newCapacity = oldCapacity + ( ( capacityIncrement > 0 ) ? capacityIncrement : oldCapacity );
jdk1.6的擴容算法:newCapacity = ( capacityIncrement > 0 ) ? ( oldCapacity + capacityIncrement ) : ( oldCapacity * 2 );
參數介紹:capacityIncrement 是容量修正(即容量新增大小),沒有設置,默認為0 ,newCapacity 是擴容后的容量大小,oldCapacity 是擴容前的大小
一觀察,就會發現1.6與1.8的寫法變化不大,但是仔細一分析,就會發現jdk1.6中有使用乘法運算,即 oldCapacity * 2。 在jdk1.8中換成了加法運算,這是因為乘法的效率是低於加法的,這應該算法的優化。
(3)LinkedList
LinkedList底層是一個雙向鏈表,它增刪快,效率高,但是查詢慢,線程不安全
實現原理:
構造器只有如下兩種;
1.無參構造 public LinkedList() { } 2.有參構造 public LinkedList(Collection<? extends E> c) { this(); addAll(c); }
由於它的底層實現是鏈表,所以沒有容量大小的定義,只有上個節點,當前節點,下個節點,每個節點都有一個上級節點和一個下級節點。
新增元素:
1.頭部新增
實現代碼如下:
private void linkFirst(E e) { final Node<E> f = first; final Node<E> newNode = new Node<>(null, e, f); first = newNode; if (f == null) last = newNode; else f.prev = newNode; size++; modCount++; }
先獲取頭部節點元素,判斷是否為null,若為null,說明原鏈表中沒有元素,則把 first 和 last 都賦為當前新增節點。
若不為null,說明原鏈表中有元素,則把first賦為當前新增節點,把原頭部節點f的上級節點修改為當前新增節點的下級節點
2.尾部新增
void linkLast(E e) { final Node<E> l = last; final Node<E> newNode = new Node<>(l, e, null); last = newNode; if (l == null) first = newNode; else l.next = newNode; size++; modCount++; }
與頭部新增元素類似,不再贅述。
刪除元素:
刪除元素有三種方式,刪除第一元素,刪除最后一個元素,刪除中間部分的某個元素。 現介紹最后一個,最后一個搞懂了,前兩個就懂了。
實現代碼:
E unlink(Node<E> x) { // assert x != null; final E element = x.item; final Node<E> next = x.next; final Node<E> prev = x.prev; if (prev == null) { first = next; } else { prev.next = next; x.prev = null; } if (next == null) { last = prev; } else { next.prev = prev; x.next = null; } x.item = null; size--; modCount++; return element; }
原理:要刪除元素的當前節點x,將當前節點x的上級節點的下級節點設為當前節點x的下級節點,將當前節點x的下級節點的上級節點設為當前節點x的上級節點。
中間考慮上級節點或下級節點為空的情況,也就是頭部刪除與尾部刪除。
