Java源碼解析之接口List
List接口是Collection接口的三大接口之一,其中的數(shù)據(jù)可以通過位置檢索,用戶可以在指定位置插入數(shù)據(jù)。List的數(shù)據(jù)可以為空,可以重復(fù)。我們來看看api文檔是怎么說的:
我們這里就只關(guān)注和Collection不同的方法,主要有以下這些:
//在指定位置,將指定的集合插入到當(dāng)前的集合中boolean addAll(int index, Collection<? extends E> c);//這是一個(gè)默認(rèn)實(shí)現(xiàn)的方法,會通過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ù)指定的規(guī)則對當(dāng)前集合進(jìn)行排序,可以看到,排序是通過Arrays這個(gè)工具類完成的。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è)元素在集合中首次出現(xiàn)的位置int indexOf(Object o);//返回一個(gè)元素在集合中最后一次出現(xiàn)的位置int lastIndexOf(Object o);//ListIterator繼承于Iterator,主要增加了向前遍歷的功能ListIterator<E> listIterator();//從指定位置開始,返回一個(gè)ListIteratorListIterator<E> listIterator(int index);//返回一個(gè)子集合[fromIndex, toIndex),非結(jié)構(gòu)性的修改返回值會反映到原表,反之亦然。//如果原表進(jìn)行了結(jié)構(gòu)修改,則返回的子列表可能發(fā)生不可預(yù)料的事情List<E> subList(int fromIndex, int toIndex);
通過對上面方法的研究,我們不難發(fā)現(xiàn),collection接口主要提供一些通常的方法,而List接口則針對線性表的結(jié)構(gòu),提供了對位置以及字表的操作。
二、超級實(shí)現(xiàn)類AbstractList我們先看看源文檔是怎么來說AbstractList的,要實(shí)現(xiàn)一個(gè)不可修改的集合,只需要復(fù)寫get和size方法。如果要實(shí)現(xiàn)一個(gè)可以修改的集合,還需要復(fù)寫set方法,如果要動態(tài)調(diào)整大小,就必須實(shí)現(xiàn)add和remove方法。
接下里我們一起來來看看源碼吧!
//在AbstractCollection中,add方法默認(rèn)會拋出異常,//而在這里是調(diào)用了add(int index, E e)方法,但這個(gè)方法也是沒有實(shí)現(xiàn)的。//這里默認(rèn)會把元素添加到末尾。public boolean add(E e) { add(size(), e); return true;}//同上,這個(gè)只需要進(jìn)行一次遍歷即可public boolean addAll(int index, Collection<? extends E> c) { //... }
接下里我們在繼續(xù)看看其他幾個(gè)方法,這幾個(gè)是與Iterator和ListIterator息息相關(guān)的,在AbstractList中有具體的實(shí)現(xiàn),我們先來看看它是如何把集合轉(zhuǎn)變成Iterator對象并支持foreach循環(huán)的吧。
我們通過源碼發(fā)現(xiàn):在Iterator方法中,是直接返回一個(gè) Itr對象
public Iterator<E> iterator() { return new Itr();}
其實(shí)我們很快也就會明白,它是實(shí)現(xiàn)了一個(gè)內(nèi)部類,這個(gè)內(nèi)部類實(shí)現(xiàn)了Iterator接口,合理的處理hasNext、next、remove方法。這個(gè)源碼就不粘貼啦,其中僅僅在remove時(shí)考慮了一下多線程問題,有興趣的可以自己去看看。
我們來看看另一個(gè)吧?ListIterator吧他也是通過一個(gè)內(nèi)部類是實(shí)現(xiàn)的
public ListIterator<E> listIterator() { return listIterator(0);}
public ListIterator<E> listIterator(final int index) { rangeCheckForAdd(index); return new ListItr(index);}
事實(shí)證明,和我們想的一樣,AbstractList內(nèi)部還定義了一個(gè)ListItr,實(shí)現(xiàn)了ListIterator接口,其實(shí)現(xiàn)也很簡單,就不粘貼源碼啦。
接下倆讓我們來看看AbtractList是怎么利用這兩個(gè)類來做事情的
//尋找一個(gè)元素首次出現(xiàn)的位置,只需要從前往后遍歷,找到那個(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è)元素最后一次出現(xiàn)的位置,只需要從列表最后一位向前遍歷即可。//看到listIterator(int index)方法是可以傳遞參數(shù)的,這個(gè)我想我們都可以照著寫出來了。public int lastIndexOf(Object o) { //...}//這個(gè)方法是把從fromIndex到toIndex之間的元素從集合中刪除。//clear()方法也是調(diào)用這個(gè)實(shí)現(xiàn)的(我認(rèn)為clear實(shí)現(xiàn)意義并不大,因?yàn)樵谄渖霞堿bstractCollection中已經(jīng)有了具體實(shí)現(xiàn))。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(); }}
在接下來讓我們來說一說兩個(gè)比較重要的內(nèi)容一個(gè)是關(guān)于SubList,另一個(gè)是關(guān)于equals和hascode的。
三、SubList、equals和hascodeSubList并不是新建了一個(gè)list,只是持有當(dāng)前集合的引用,然后控制了用戶可以操作的范圍,所以在接口定義時(shí)就說明了其更改會直接反應(yīng)到原集合中。SubList是定AbstractList內(nèi)部,并且是AbstractList的基礎(chǔ)上增加了對可選范圍的控制。
而equals和hascode的實(shí)現(xiàn),也關(guān)乎我們的使用。在AbstractList中,這兩個(gè)方法不僅與其實(shí)例有關(guān),也和其內(nèi)部包含的元素有關(guān),所以在定義數(shù)據(jù)元素時(shí),也應(yīng)該復(fù)寫這兩個(gè)方法,以保證程序的正確運(yùn)行。這里看下其源碼加深一下印象吧。
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();//這里用到了數(shù)據(jù)元素的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)//這里用到了數(shù)據(jù)元素的hashCode方法hashCode = 31*hashCode + (e==null ? 0 : e.hashCode()); return hashCode;}
到此這篇關(guān)于Java源碼解析之接口List的文章就介紹到這了,更多相關(guān)Java接口List內(nèi)容請搜索好吧啦網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持好吧啦網(wǎng)!
相關(guān)文章:
1. python如何實(shí)現(xiàn)word批量轉(zhuǎn)HTML2. PHP如何打印跟蹤調(diào)試信息3. Java8內(nèi)存模型PermGen Metaspace實(shí)例解析4. XML入門的常見問題(二)5. HTML <!DOCTYPE> 標(biāo)簽6. CSS3實(shí)例分享之多重背景的實(shí)現(xiàn)(Multiple backgrounds)7. 小技巧處理div內(nèi)容溢出8. 匹配模式 - XSL教程 - 49. 存儲于xml中需要的HTML轉(zhuǎn)義代碼10. HTML DOM setInterval和clearInterval方法案例詳解
