Thinking in Java:容器深入研究

來源:互聯網
上載者:User

Thinking in Java:容器深入研究

編程風格而言,應該在覆蓋equals方法時,總是同時覆蓋hashCode()方法。

3.如果一個對象被用於任何種類的排序容器中,如SortedSet(TreeSet是其唯一實現),則其必須實現Comparable介面
PS:在介面的實現方法compareTo()中,不應該使用return i-i2這樣的形式,錯誤編程,因為這樣沒有考慮到i-i2數值溢出的問題,應該
return (arg.i < i ? -1 : (arg.i == i ? 0 : 1))

4若在HashSet容器中元素並沒有重新定義hashCode(),將它們放置到任何散列實現中都可能會產生重複值,這甚至不會產生執行階段錯誤。唯一的可靠方法就是寫單測。

5.SortedSet的意思為“按照對象的比較函數對元素排序”,而不是“元素插入的次序”。

6.優先順序隊列,其元素排序次序也是通過實現Comparable而進行控制的。

理解Map:
1:HashMap : 基於散列表的實現。可以通過構造器設定容量和負載因子調整容器效能。
2:LinkedHashMap :與HashMap卻別在於迭代遍曆時,取得索引值對順序是插入次序,或是LRU次序。除了迭代訪問時其餘效能要慢一點
3:TreeMap:基於紅/黑樹狀結構的實現。查看“鍵”或者“索引值對”的時候,它們會被排序(按照Comparable方法),其唯一的帶有subMap()方法的Map,可以返回一個子樹。
4:WeakHashMap:弱鍵映射,允許釋放映射所指向的對象;如果映射之外沒有引用指向某個“鍵”,則此鍵可以被垃圾收集器回收
5:IdentityHashMap:使用==代替equals()對”鍵“進行比較的散列映射
PS:任何鍵都必須具有一個equals方法,如果鍵被用於散列Map,則還必須有一個恰當的hashCode方法;若鍵被用於TreeMap,則它必須實現Comparable

7.map中可以直接列印values方法的結果,該方法會產生一個包含Map中所有值得Collection,由於這些Collection背後是由Map支援的,所以對Collection的任何改動都會反映到與之相關聯的Map。

8.LinkedHashMap散列化所有的元素,但是在遍曆索引值對時,卻又以元素的插入順序返回索引值對,此外,可以在構造器中設定LinkedHashMap,使之採用基於訪問的LRU演算法,於是沒有被訪問過的元素就會出現在隊列的前面。對於需要定期清理元素以節省空間的程式來說,此功能使得程式很容易得以實現。

散列與散列碼:
1.Object的hashCode()方法產生散列碼,而它預設是使用對象的地址計算散列碼。
2.可能你會認為,只需編寫恰當的hashCode()方法的覆蓋版本即可。但是它仍然無法正常運行,除非你同時覆蓋equals()方法,他也是Object的一部分。HashMap使用equals()判斷當前的鍵是否與表中存在的鍵相同。
PS:正確的equals()方法必須滿足下列5個條件:
1)自反性:x.equals(x)一定返回true
2)對稱性:x.equals(y)返回true若且唯若y.equals(x)
3)傳遞性:x.equals(y)且y.equals(z),則x.equals(z)為true
4)一致性:若x.equals(y)返回true,則不改變x,y時多次調用x.equals(y)都返回true
5)對於任意的非Null 參考值x,x.equals(null)一定返回false。

為了速度而散列:
1.由於瓶頸位於鍵的查詢速度,因此解決方案之一就是保持鍵的排序狀態,然後使用Collections。binarySearch()進行查詢
2.散列則更進一步,它將鍵儲存在某處,以便能夠很快找到。儲存一組元素最快的資料結構是數組,所以使用它來表示鍵的資訊。資訊就是散列碼。
3.通常,衝突由外部連結處理,數組並直接儲存至,而是儲存值得list,然後對list中的值使用equals方法進行線性查詢。
4.進來,Java的散列函數都使用2的整數次方。對現代的處理器來說,除法與求餘數是最慢的操作。使用2的整數次方長度的散列表,可用掩碼代替除法。因為get是使用最多的操作,求餘數的%操作是其開銷最大的部分,而是用2的整數次方可以消除此開銷。

9.設計hashCode()時最重要的因素就是:無論何時,對同一個對象調用hashCode()都應該產生同樣的值。若你的hashCode()方法依賴於對象中易變的資料,使用者就要當心了。同時,也不應該使hashCode()依賴於具有唯一性的對象資訊,尤其是使用this的值,這隻能產生很糟糕的hashCode()因為這樣無法產生一個新的鍵使之與put中原始的索引值對中的鍵相同。

10.要想使hashCode使用,他必須速度快,並且有意義,也就是說,他必須基於對象的內容產生散列碼。散列碼不必是獨一無二的,但是通過hashCode()和equals,必須能夠完全確定對象的身份。

效能:
1.應該避免使用Vector(能正常工作的唯一原因,只是為了向前相容,被適配成了List)
2TreeSet迭代通常比用HashSet要快;另外,對於插入操作,LinkedHashSet比HashSet代價更高,這是由維護鏈表所帶來額外的開銷造成的
3.Hashtable的效能大體上與HashMap相當。因為HashMap是用來替代Hashtable的。因此它們使用了相同的底層儲存和尋找機制。
4.IdentityHashMap則具有完全不同的效能,因為它使用==而不是equals來比較元素。

HashMap的效能因子:
容量:表中桶位元(slot)
初始容量:表在建立時所擁有的桶位元。HashMap和HashSet都具有允許你只能初始容量的構造器。
尺寸:表中當前儲存的項數。
負載因子:尺寸/容量。HashMap和HashSet都具有允許你指定負載因子的構造器,表示負載情況達到該負載因子的水平時,容器將自動添加其容量(桶位元),實現方式是使容量大致加倍,並重新將現有對象分布到新的桶位元集中(這被稱為再散列)

Collection或Map的同步控制:
1.Collections類有辦法能夠自動同步整個容器。其文法與“unmodified*”類似。
List a = Collections.synchronizedList(new ArrayList(data));
最好如上所示,是直接將新產生的容器傳遞給了適當的“同步”方法,這樣做就不會有任何機會會暴漏出不同步的版本。

快速報錯:
Java容器有一種保護機制,能夠防止多個進程同時修改同一個容器的內容。Java容器類類庫採用快速報錯(fail fast)機制。它會探查容器上的任何除了你的進程所進行的操作以外的所有變化,一旦發現其他進程改變了容器,就會立刻拋出ConcurrentModificationException異常。如:在容器取得迭代器之後,又有東西唄放入到了該容器中
ConcurrentHashMap,CopyOnWriteArrayList、CopyOnWriteArraySet都使用了可以避免ConcurrentModificationException的技術

持有引用:
1.java.lang.ref類庫包含一組類,當存在可能會耗盡記憶體的大對象的時候,這些類顯得特別有用。有SoftReference、WeakReference、PhantomReference。當記憶體回收期正在考察的對象只能通過某個Reference對象才“可獲得時”,上述這些不同的衍生類別為記憶體回收行程提供了不同層級的間接性指示
2.如果想繼續持有對某個對象的引用,希望以後還能夠訪問到該對象,但是也希望能夠允許記憶體回收行程釋放它,這時就應該使用Reference對象。這樣,你可以繼續使用對象,而在記憶體消耗殆盡的時候又允許釋放該對象。
3.以Reference對象作為你和普通引用之間的媒介(代理),另外一定不能有普通的引用指向那個對象,這樣就能達到上述目的
4.對於SoftReference、WeakReference、PhantomReference三個引用的區別和功能,詳見JVM.
5.使用SoftReference、WeakReference時,可以選擇是否要將它們放入ReferenceQueue(用作“回收前清理工作”的工具,見JVM)。而PhantomReference只能依賴於ReferenceQueue。
6.WeakHashMap:見JVM,它被用來儲存WeakReference。這該映射中,每個值只儲存一份執行個體以節省儲存空間,且WeakHashMap允許記憶體回收行程自動清理鍵和值,所以它顯得十分便利。

Java 1.0/1.1容器(瞭解):
1.Enmuberation:老版本的迭代器,其介面比Iterator小,但是無論如何代碼中應該盡量使用Iterator。可以通過使用Collections.enumeration()方法來從Collection產生一個Enumeration
2.Hashtable:如前所說,基本的Hashtable與HashMap很相似。盡量使用HashMap(多線程同步時仍然有很多其他的選擇)
3.BisSet:如果想要高效率地儲存大量“開/關”資訊,BitSet是很好的選擇。不過它的效率僅是對空間而言;如果需要高效訪問時間,BitSet比本地數組稍慢一些,BitSet最小容量是Long:64位,若儲存的內容比較小,如8位,則BitSet浪費了一些空間。BitSet也會想普通容器一樣隨著元素的加入而擴充其容量。總的來說,若擁有一個可以命名的標誌集合,那麼EnumSet通常是一種更好的選擇,因為EnumSet允許你按照名字而不是數字位的位置進行操作,因此可以減少錯誤。

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.