在複習過程中深感之前的學習不繫統,而且不能再像剛畢業那樣死背面試題,例如:String是固定長度的,StringBuffer和StringBuilder的長度卻能改變的。如果一旦問得深入一點,問為什麼有這樣的差異就傻眼了,只能一臉呆萌地看著面試官。
因此想要透過寫文章的形式,有系統地總結學習的內容,例如Collection架構是怎樣的、有哪些相關的繼承和介面實現,這樣才能了解什麼時候應該用哪個類,以及類別之間要如何搭配合作,才知道出了問題該如何解決。 這一系列文章適用於Java技術職位的申請者、大學電腦專業的學生、培訓機構學習Java的初學者閱讀。
1.1 認識Collection架構
我們都用過ArrayList類別收集對象,例如add()方法新增對象,remove()方法移除對象,這些都不會陌生。但是這些方法是怎麼來的呢?下圖是該類別的繼承架構圖:
ArrayList一個類別就這麼複雜,如果要把全部Collection架構表現在一張圖上,那估計就跟蜘蛛網一樣糾纏不清。簡化一下,忽略一些不那麼重要的介面和實作類,我們可以得到以下這張架構圖。
#
從圖上可知,Colletion是一個接口,實作了另一個接口Iterable。 Collection下面有三個介面直接實作了它,分別是List、Set和Queue。 List下面有兩個實作類,分別是ArrayList和LinkedList;Set的常用實作類別是TreeSet和HashSet;Queue下面有Deque介面實現,再下面是實作類別ArrayDeque.
#這張圖將會是這一系列文章的核心,之後會一再提及,不妨稱之為Collection架構圖,每一篇文章都是介紹其中的一部分。熟悉這張圖,不僅有助於理解學習,還可以幫助記憶。至於詳細周全的繼承關係和實作架構,到底有哪些類別實作了哪些介面、繼承了哪些類,可以自行在API說明文件中查詢。
1.2 具有索引的List
List實作了Collection接口,所以我們可以說List是一種Colletion,作用就是收集對象,特點是以索引的方式記錄所收集的對象順序。 List常見的實作類別是剛才所提及架構圖中的ArrayList,忘了的讀者可以翻到前面對照著看。
1 /** 2 * ArrayList的实验用例 3 */ 4 5 import java.util.*; 6 7 public class Student { 8 public static void main(String[] args) { 9 List list = new ArrayList(); //使用JavaSE的List和ArrayList10 Scanner scanner = new Scanner(System.in);11 String name;12 while(true) {13 System.out.print("学生签到:");14 name = scanner.nextLine();15 if(name.equals("quit")) {16 break;17 }18 list.add(name); //实用Add()方法收集对象19 }20 System.out.println("今天上来上课的学生名单:");21 foreach(list);22 }23 24 private static void foreach(List list) {25 for(int i = 0; i < list.size(); i++) {26 String student = (String) list.get(i); //使用get()方法依据索引取得收集的对象27 System.out.println(student);28 }29 }30 }
以上是ArrayList类的一个简单使用例子,模拟的是学生上课签到的情景。强烈建议读者跟我一样自己试着写一个简单用例,尤其是之前很少使用ArrayList的初学者,单纯的看和读跟实际敲代码产生的效果完全不一样。也可以照着我给出的例子敲,偷懒一点的话可以直接复制在机器上跑一遍。
从Collection架构图中可知,LinkedList同样也实现了List接口。就算只是把上面那个实验中的ArrayList全部改为LinkedList,程序照样可以运作,而且效果看起来完全相同。那么问题来了,我们什么时候应该使用ArrayList,什么时候又应该使用LinkedList呢?
1.2.1 ArrayList的特性
卡车和轮船都可以运送货物,我们可以根据不同的情况选择不同的运输方式。如果时间紧、运输量小,而且两个地点都在陆地上(例如北京到南京),那么我们可以使用汽车;如果时间多、运输量大,出发地和目的之间隔着海洋(例如大连到纽约),那么用船运是更好的选择。
刚毕业那会要找工作,为了面试背过“ArrayList像数组,读取速度快,但是需要调整索引的话表现很差;LinkedList像链表,调整索引的表现非常好,但是随机读取的速度比较慢”。那么我们可以问深一句,为什么会这样呢?不妨从源代码中找寻答案。
1 public boolean add(E e) {2 ensureCapacityInternal(size + 1); // Increments modCount!!3 elementData[size++] = e;4 return true;5 }
上面这一段是JavaSE的源代码,我们可以看到ArrayList中的add()方法非常简单,跟我们平时使用数组一样。查看源代码中更多内容你会发现,ArrayList内部就是使用Object数组来保存所收集的对象,这就是为什么说“ArrayList就像数组”的原因。在考虑是否使用ArrayList的时候,我们可以相当于考虑是否要使用数组的特性。
1.2.2 LinkedList的特性
在学习Collection架构的时候,我们不妨可以多看源代码,看的时候优先比较几个基本方法的实现,例如add()、remove()等。从这些方法的实现,我们就可以看到不同实现类的特性。
public boolean add(E e) { linkLast(e);return true; }/** * Links e as last element. */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;elsel.next = newNode; size++; modCount++; }
看到LinkdedList.add()的源代码,我们会发现其实现方式跟链表的实现如出一辙。如果last结点为null,那么说明链表为空,所以新添加的结点为头结点。如果last结点不等于null,那么把新添加的结点设为last的下一个结点,作为新的尾结点。
根据链表的特性,我们可以很快总结两点点特性:1.想要指定索引随机存取时,链接方式都得使用从第一个元素开始查找下一个元素的方式,效率比较糟糕;2.链接的每个元素都会参考下一个元素,这有利于调整索引顺序。
1.2.3 List总结
作为Collection三大阵营之一的List,最大的特点就是索引,我们可以通过索引做到随机存取。
List中常用的实现有ArrayList和LinkedList,各自的特性可以分别参考数组和链表。在比较它们之间区别的过程中,我们看了源代码,提倡在比较同一接口不同实现类时重点查看它们共同需要实现的方法,例如Collection中规定的add(),remove()等。
面试中常见的List实现类其实还有Vector,其特性与ArrayList相同。不同在于Vector具有线程安全的特性,性能开销比较大,具体的内容会放在以后关于多线程的文章里。
以上是JavaSE中Collection的實例講解的詳細內容。更多資訊請關注PHP中文網其他相關文章!