- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- Java源碼解析之接口List
List接口是Collection接口的三大接口之一,其中的數據可以通過(guò)位置檢索,用戶(hù)可以在指定位置插入數據。List的數據可以為空,可以重復。我們來(lái)看看api文檔是怎么說(shuō)的:
我們這里就只關(guān)注和Collection不同的方法,主要有以下這些:
//在指定位置,將指定的集合插入到當前的集合中 boolean addAll(int index, Collection<? extends E> c); //這是一個(gè)默認實(shí)現的方法,會(huì )通過(guò)Iterator的方式對每個(gè)元素進(jìn)行指定的操作 default void replaceAll(UnaryOperator<E> operator) { Objects.requireNonNull(operator); final ListIterator<E> li = this.listIterator(); while (li.hasNext()) { li.set(operator.apply(li.next())); } } //排序,依據指定的規則對當前集合進(jìn)行排序,可以看到,排序是通過(guò)Arrays這個(gè)工具類(lèi)完成的。 default void sort(Comparator<? super E> c) { Object[] a = this.toArray(); Arrays.sort(a, (Comparator) c); ListIterator<E> i = this.listIterator(); for (Object e : a) { i.next(); i.set((E) e); } } //獲取指定位置的元素 E get(int index); //修改指定位置元素的值 E set(int index, E element); //將指定元素添加到指定的位置 void add(int index, E element); //將指定位置的元素移除 E remove(int index); //返回一個(gè)元素在集合中首次出現的位置 int indexOf(Object o); //返回一個(gè)元素在集合中最后一次出現的位置 int lastIndexOf(Object o); //ListIterator繼承于Iterator,主要增加了向前遍歷的功能 ListIterator<E> listIterator(); //從指定位置開(kāi)始,返回一個(gè)ListIterator ListIterator<E> listIterator(int index); //返回一個(gè)子集合[fromIndex, toIndex),非結構性的修改返回值會(huì )反映到原表,反之亦然。 //如果原表進(jìn)行了結構修改,則返回的子列表可能發(fā)生不可預料的事情 List<E> subList(int fromIndex, int toIndex);
通過(guò)對上面方法的研究,我們不難發(fā)現,collection接口主要提供一些通常的方法,而List接口則針對線(xiàn)性表的結構,提供了對位置以及字表的操作。
我們先看看源文檔是怎么來(lái)說(shuō)AbstractList的,要實(shí)現一個(gè)不可修改的集合,只需要復寫(xiě)get和size方法。如果要實(shí)現一個(gè)可以修改的集合,還需要復寫(xiě)set方法,如果要動(dòng)態(tài)調整大小,就必須實(shí)現add和remove方法。
接下里我們一起來(lái)來(lái)看看源碼吧!
//在A(yíng)bstractCollection中,add方法默認會(huì )拋出異常, //而在這里是調用了add(int index, E e)方法,但這個(gè)方法也是沒(méi)有實(shí)現的。 //這里默認會(huì )把元素添加到末尾。 public boolean add(E e) { add(size(), e); return true; } //同上,這個(gè)只需要進(jìn)行一次遍歷即可 public boolean addAll(int index, Collection<? extends E> c) { //... }
接下里我們在繼續看看其他幾個(gè)方法,這幾個(gè)是與Iterator和ListIterator息息相關(guān)的,在A(yíng)bstractList中有具體的實(shí)現,我們先來(lái)看看它是如何把集合轉變成Iterator對象并支持foreach循環(huán)的吧。
我們通過(guò)源碼發(fā)現:在Iterator方法中,是直接返回一個(gè) Itr對象
public Iterator<E> iterator() { return new Itr(); }
其實(shí)我們很快也就會(huì )明白,它是實(shí)現了一個(gè)內部類(lèi),這個(gè)內部類(lèi)實(shí)現了Iterator接口,合理的處理hasNext、next、remove方法。這個(gè)源碼就不粘貼啦,其中僅僅在remove時(shí)考慮了一下多線(xiàn)程問(wèn)題,有興趣的可以自己去看看。
我們來(lái)看看另一個(gè)吧–ListIterator吧他也是通過(guò)一個(gè)內部類(lèi)是實(shí)現的
public ListIterator<E> listIterator() { return listIterator(0); }
public ListIterator<E> listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index); }
事實(shí)證明,和我們想的一樣,AbstractList內部還定義了一個(gè)ListItr,實(shí)現了ListIterator接口,其實(shí)現也很簡(jiǎn)單,就不粘貼源碼啦。
接下倆讓我們來(lái)看看AbtractList是怎么利用這兩個(gè)類(lèi)來(lái)做事情的
//尋找一個(gè)元素首次出現的位置,只需要從前往后遍歷,找到那個(gè)元素并返回其位置即可。 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; } //同理,尋找一個(gè)元素最后一次出現的位置,只需要從列表最后一位向前遍歷即可。 //看到listIterator(int index)方法是可以傳遞參數的,這個(gè)我想我們都可以照著(zhù)寫(xiě)出來(lái)了。 public int lastIndexOf(Object o) { //... } //這個(gè)方法是把從fromIndex到toIndex之間的元素從集合中刪除。 //clear()方法也是調用這個(gè)實(shí)現的(我認為clear實(shí)現意義并不大,因為在其上級AbstractCollection中已經(jīng)有了具體實(shí)現)。 protected void removeRange(int fromIndex, int toIndex) { ListIterator<E> it = listIterator(fromIndex); for (int i=0, n=toIndex-fromIndex; i<n; i++) { it.next(); it.remove(); } }
在接下來(lái)讓我們來(lái)說(shuō)一說(shuō)兩個(gè)比較重要的內容一個(gè)是關(guān)于SubList,另一個(gè)是關(guān)于equals和hascode的。
SubList并不是新建了一個(gè)list,只是持有當前集合的引用,然后控制了用戶(hù)可以操作的范圍,所以在接口定義時(shí)就說(shuō)明了其更改會(huì )直接反應到原集合中。SubList是定AbstractList內部,并且是AbstractList的基礎上增加了對可選范圍的控制。
而equals和hascode的實(shí)現,也關(guān)乎我們的使用。在A(yíng)bstractList中,這兩個(gè)方法不僅與其實(shí)例有關(guān),也和其內部包含的元素有關(guān),所以在定義數據元素時(shí),也應該復寫(xiě)這兩個(gè)方法,以保證程序的正確運行。這里看下其源碼加深一下印象吧。
public boolean equals(Object o) { if (o == this) return true; if (!(o instanceof List)) return false; ListIterator<E> e1 = listIterator(); ListIterator<?> e2 = ((List<?>) o).listIterator(); while (e1.hasNext() && e2.hasNext()) { E o1 = e1.next(); Object o2 = e2.next(); //這里用到了數據元素的equals方法 if (!(o1==null ? o2==null : o1.equals(o2))) return false; } return !(e1.hasNext() || e2.hasNext()); }
public int hashCode() { int hashCode = 1; for (E e : this) //這里用到了數據元素的hashCode方法 hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); return hashCode; }
到此這篇關(guān)于Java源碼解析之接口List的文章就介紹到這了,更多相關(guān)Java接口List內容請搜索腳本之家以前的文章或繼續瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站