一點一點看JDK源碼(一)Collection體系概覽
liuyuhang原創,未經允許進制轉載
本文舉例使用的是JDK8的API
目錄:一點一點看JDK源碼(〇)
1.綜述
Collection為集合類,是jdk中最為常用的類了,實際上我並不認同這個東西叫做集合
我更傾向於叫做容器,當然容器不止有它一種。
在計算機專業中,大概都會學一門叫做《數據結構》的課程吧
本質上來說,數據結構,實際上是設計一種容器,而容器的特性大體包括如下:
- 容器中如何進行存儲
- 容器中的數據如何獲取
- 容器中的數據如何添加
- 容器中的數據如何遍歷
- 器中的數據如何搜索
- 容器中的其他特性(判空,替換,排序,溢出,並發,同步,拆分,匯聚等等)
在我的眼中,Collection是容器的框架集,其中包含了我們經常使用的容器,
2.Collection的關注點
Collection隸屬於java.util包。在本文中不討論concurrent包或其他派生集合體系,只討論基礎
從Collection類的原碼類注釋@see中可看到,集合體系的大概設計中重點關注的如下:
- Set(接口)
- List(接口)
- Map(接口)
- SortedSet(接口)
- SortedMap(接口)
- HashSet(類)
- TreeSet(類)
- ArrayList(類)
- LinkedList(類)
- Vector(類)
- Collections(類)
- Arrays(類)
- AbstractCollection(抽象類)
之所以只關注這些,主要有兩方面原因:
①我們的時間和技術水平有限,不可能完整的看完JDK
②JDK中的任何設計都是迭代產生的,我們沒有必要看舊版本而不更新的類
接下來將依照上述內容,從接口底層給它從頭扒到尾,雖然說Collection中@see的是這些
但是關注點肯定不止於此。
3.Collection剖析
先上Collection源碼,去掉原doc注釋,我想寫的內容直接寫在貼出來的代碼中作為注釋了。
1 public interface Collection<E> extends Iterable<E> { 2 // Query Operations 原注釋,不明意義 3 4 //定義size方法,應返回size大小,最大值為Integer.MAX_VALUE 5 int size(); 6 7 //定義isEmpty方法,用於返回是否為空 8 boolean isEmpty(); 9 10 //定義contains方法,判斷一個obj是否屬於此集合 11 boolean contains(Object o); 12 13 //定義迭代器方法,返回一個迭代器對象 14 Iterator<E> iterator(); 15 16 //定義轉換為轉換Obj數組的方法,返回一個obj數組 17 Object[] toArray(); 18 19 //定義轉換為泛型T數組的方法,返回一個指定泛型的數組 20 <T> T[] toArray(T[] a); 21 22 //定義add方法,添加一個元素e,並返回添加成功標志 23 boolean add(E e); 24 25 //定義remove方法,移除一個元素obj,並返回移除元素成功標志 26 boolean remove(Object o); 27 28 //定義containsAll方法,判斷是否包含集合實例對象c 29 boolean containsAll(Collection<?> c); 30 31 //定義addAll方法,添加集合實例對象c到本實例中 32 boolean addAll(Collection<? extends E> c); 33 34 //定義removeAll方法,從本實例中移除集合實力對象c 35 boolean removeAll(Collection<?> c); 36 37 38 /** 39 * jdk8新增 40 * 大意為: 41 * 定義removeIf方法,該方傳遞參數為函數式,傳遞內容是一個接口類型,該接口類型 42 * 定義為一個filter函數,該函數用於傳遞給Objects.requireNonNull判斷,然后調用 43 * 迭代器,將滿足該定義的filter的本實例中的元素移除 44 * @since 1.8 45 */ 46 default boolean removeIf(Predicate<? super E> filter) { 47 Objects.requireNonNull(filter); 48 boolean removed = false; 49 final Iterator<E> each = iterator(); 50 while (each.hasNext()) { 51 if (filter.test(each.next())) { 52 each.remove(); 53 removed = true; 54 } 55 } 56 return removed; 57 } 58 59 //定義retainAll方法,取本例與集合實例c的交集,判斷交集元素數量是否大於0 60 boolean retainAll(Collection<?> c); 61 62 //定義clear方法,清除本例集合中的所有元素 63 void clear(); 64 65 // Comparison and hashing 原注釋,不明意義 66 67 //不解釋 68 boolean equals(Object o); 69 70 //定義hashCode方法,獲取hashCode標記的方法 71 int hashCode(); 72 73 /** 74 *jdk8新增 75 *大意為: 76 *將迭代器拆分,重寫自Iterable接口,從已知元素數量的本例中返回拆分后的迭代器 77 *此方法返回的為本類本身 78 *子類可能重寫迭代器拆分,將一個集合的迭代拆分為多個集合的迭代交由多個線程 79 * @since 1.8 80 */ 81 @Override//重寫父類 82 default Spliterator<E> spliterator() { 83 return Spliterators.spliterator(this, 0); 84 } 85 86 /** 87 * jdk8新增 88 * 大意為: 89 * 將默認的迭代器拆分后的結果,聚合為流,該流並非io中的流, 90 * 是一種類似於數據排序操作流 91 * @since 1.8 92 */ 93 default Stream<E> stream() { 94 return StreamSupport.stream(spliterator(), false); 95 } 96 97 /** 98 * jdk8新增 99 * 同上,但是具體其他的實現中,因為可並行,所以可能是線程不安全的 100 * 101 * @since 1.8 102 */ 103 default Stream<E> parallelStream() { 104 return StreamSupport.stream(spliterator(), true); 105 }
以上代碼對Collection接口中的方法進行了簡單的解釋,同時對java8新增的一些方法也進行了簡單的解釋。
因為定義的都是接口,實際實現的方法非常的少,
而應java8多線程的特性提供的一些default方法也有子類去實現。
在堆Collection接口中的源碼進行了解的同時,不要忘記此接口繼承了Iterable接口。
因此Iterable接口也必定要看一下的,內容比較少,但是通過源碼的剖析,發現了集合類的共性:
集合作為容器,其體系中的所有集合都包括了:
大小(size),判空(isEmpty),添加元素(add),刪除元素(remove),是否包含(contains)
轉換數組(toArray),清空(clear),遍歷與迭代(forEach(父接口中),iterator)
是否相同(equals),哈希(hashCode),求交集(retainAll)
除此之外,提供了java8的分離接口,聚合接口,為了大容量集合的多線程操作
注意,Collection接口並沒有重寫父接口的forEach方法,而iterator方法雖然有出現,但是沒有@Override注解
同樣貼一下代碼,同樣的去掉原doc注釋,我想寫的內容直接寫在貼出來的代碼中作為注釋了。
1 public interface Iterable<T> { 2 3 //定義iterator方法,返回迭代器 4 Iterator<T> iterator(); 5 6 /** 7 * jdk8新增 8 * 大意為: 9 * 根據action調用Objects.requireNonNull進行過濾 10 * 過濾結果調用for循環取出, 11 * @since 1.8 12 */ 13 default void forEach(Consumer<? super T> action) { 14 Objects.requireNonNull(action); 15 for (T t : this) { 16 action.accept(t); 17 } 18 } 19 20 /** 21 * jdk8新增 22 * 大意為: 23 * 分離迭代器,將未知大小的迭代器進行拆分,返回拆分的迭代器本身 24 * 25 * @since 1.8 26 */ 27 default Spliterator<T> spliterator() { 28 return Spliterators.spliteratorUnknownSize(iterator(), 0); 29 } 30 }
有時候我們並不怎么關心父接口的問題,但是實際上這個問題有點重要的還是,上兩張圖解釋一下:


不要以為以上兩種接口定義實現類的方式沒區別,實際上有區別,區別大了,可實現的方法列表有差異
該問題具體解析,將在后續更新中詳細寫代碼測試。
Collection接口內容較少,多數都只是定義了必要內容,具體實現較少。難點都在java8中的default方法上了
等以后弄徹底明白了可能再寫通俗解釋和常用方式。
明天更對於List接口的剖析和ArrayList的簡要剖析!
以上!
