更好閱讀體驗:Java集合為什麼設計為:實現類繼承了抽象類,同時實現抽象類實現的介面
Java集合原始碼為什麼設計為:「實現類繼承了抽象類,同時實現抽象類實現的介面?」
看著List 集合的UML圖來分析
如圖:介面+抽象類都是成對出現,Collection 和 AbstractCollection;List 和 AbstractList。ArrayList 繼承了AbstractList,同時實現了List 介面。
再看下其他集合的UML 圖,看看是不是也是這樣設計的
這樣設計的意義
有的人說介面只能使用抽象方法,為了實現公共的方法抽出來用抽象類來實現,提高程式碼複用性,提高程式碼質量。
其實不是,第一句就錯了,介面同樣是可以實現方法,用的關鍵字是 default。如果真的是為了公共的實現方法抽出來用抽象類來實現,那還不如直接在介面上實現不更好,而且具體的實現類(如:ArrayList)還不用繼承抽象類,畢竟繼承還是單一的。
List 介面繼承了Collection 介面絕大部分方法,並新定義了List 特有的抽象方法,而這些特有的抽象方法都交給了AbstractList 來實現。
抽兩個方法來看看
// AbstractList public void add(int index, E element) { throw new UnsupportedOperationException(); } public E remove(int index) { throw new UnsupportedOperationException(); }
在AbstractList中,這兩個方法只是拋了個“不支援的操作異常”,並沒有具體的內容。要明白抽象類是多種類的再一次抽象,也就是說具體的實現方法還是要針對不同的類來編寫,所以還要看看ArrayList 和 LinkedList 對add(int index, E element)的具體實現
// ArrayList public void add(int index, E element) { rangeCheckForAdd(index); ensureCapacityInternal(size + 1); // Increments modCount!! System.arraycopy(elementData, index, elementData, index + 1, size - index); elementData[index] = element; size++; } // LinkedList public void add(int index, E element) { checkPositionIndex(index); if (index == size) linkLast(element); else linkBefore(element, node(index)); }
可見,這兩個方法的實現完全不同(底層資料結構不同),到此應該明白一點了:「List 介面定義個List 特有的規範,AbstractList 對這個規範做了通用實現,而具體實現還是要在具體類裡面落實」。但並不是只是為了高複用性、減少程式碼重複度。
比如:public int indexOf(Object o); 雖然抽象類實現了,但具體類還是重寫了這方法,顯然不是為了解決程式碼複用的問題,而是提供了通用實現,具體的還有看具體類使用了什麼型別的資料結構,然後在具體類中重寫方法定製化的實現。
// AbstractList public int indexOf(Object o) { ListIterator<E> it = listIterator(); if (o==null) { while (it.hasNext()) if (it.next()==null) return it.previousIndex(); } else { while (it.hasNext()) if (o.equals(it.next())) return it.previousIndex(); } return -1; } // ArrayList public int indexOf(Object o) { if (o == null) { for (int i = 0; i < size; i++) if (elementData[i]==null) return i; } else { for (int i = 0; i < size; i++) if (o.equals(elementData[i])) return i; } return -1; } // LinkedList public int indexOf(Object o) { int index = 0; if (o == null) { for (Node<E> x = first; x != null; x = x.next) { if (x.item == null) return index; index++; } } else { for (Node<E> x = first; x != null; x = x.next) { if (o.equals(x.item)) return index; index++; } } return -1; }
意義
1.介面實現的解耦:介面新增或刪除方法時,只需在抽象類中做個方法初始實現(對於刪除方法可以不做處理),即可避免一個介面變動導致所有實現類都需要更新程式碼的問題。
2.多型特性的運用,向上轉型:ArrayList 、Vector、LinkedList 都可以實現對資料的儲存,都可以用List 作為引用(面向介面程式設計)。
「總結」
-
提高介面的靈活性:介面只需要按需重寫方法;
-
提高介面的易擴充套件:介面變動不影響實現類,只需要更改相應的抽象類實現即可;
-
抽象類和介面的互補:介面規定行為規範,抽象類補充屬性和介面實現的解耦。
個人理解,如有不對,還望糾正。