1. 程式人生 > >HashSet原始碼探討(基於JDK1.8)

HashSet原始碼探討(基於JDK1.8)

HashSet 簡介 如果對HashMap沒有了解,應該先學習HashMap再學習HashSet 。
HashSet結構
  1. publicclassHashSet<E>
  2. extendsAbstractSet<E>
  3. implementsSet<E>,Cloneable, java.io.Serializable
HashSet基於HashMap實現 HashSet 是一個沒有重複元素的集合,它其實是由HashMap實現的,HashMap中儲存的是鍵值對,然而我們只能向HashSet中新增key,原因在於 HashSet的Value其實都是同一個物件,這是HashSet新增元素的方法,可以看到輔助實現HashSet的map中的value其實都是Object類的
同一個物件。
  1. private static final Object PRESENT = new Object();
  2. publicboolean add(E e){
  3. return map.put(e, PRESENT)==null;
  4. }
HashSet的執行緒不安全性
HashSet不保證元素的順序,而且HashSet允許使用 null 元素。
HashSet是非同步的,這也意味著HashSet是執行緒不安全的。如果多個執行緒同時訪問一個HashSet,而其中至少一個執行緒修改了該HashSet,那麼它必須保持外部同步。這通常是通過對自然封裝該 HashSet的物件執行同步操作來完成的。如果不存在這樣的物件,則應該使用 Collections.synchronizedSet 方法來“包裝” Set。最好在建立時完成這一操作,以防止對該 set 進行意外的不同步訪問:
  1. publicstatic<T>Set<T> synchronizedSet(Set<T> s){
  2. returnnewSynchronizedSet<>(s);
  3. }
SynchronizedSet如下
  1. staticclassSynchronizedSet<E>
  2. extendsSynchronizedCollection<E>
  3. implementsSet<E>{
  4. privatestaticfinallong serialVersionUID =487447009682186044L;
  5. SynchronizedSet
    (Set<E> s){
  6. super(s);
  7. }
  8. SynchronizedSet(Set<E> s,Object mutex){
  9. super(s, mutex);
  10. }
  11. publicboolean equals(Object o){
  12. if(this== o)
  13. returntrue;
  14. synchronized(mutex){return c.equals(o);}
  15. }
  16. publicint hashCode(){
  17. synchronized(mutex){return c.hashCode();}
  18. }
  19. }
HashSet的兩種遍歷方式
  1. publicclassHashSetIteratorTest{
  2. privatestaticfinalint ADD_NUM =100000;
  3. publicstaticvoid main(String[] args){
  4. HashSet set =newHashSet();
  5. for(int i=0; i<ADD_NUM; i++)
  6. set.add(""+i);
  7. // 通過Iterator遍歷HashSet
  8. iteratorHashSet(set);
  9. // 通過for-each遍歷HashSet
  10. foreachHashSet(set);
  11. }
  12. privatestaticvoid iteratorHashSet(HashSet set){
  13. long start =System.currentTimeMillis();
  14. for(Iterator iterator = set.iterator();
  15. iterator.hasNext();){
  16. System.out.print(iterator.next());
  17. }
  18. System.out.println();
  19. long end =System.currentTimeMillis();
  20. System.out.println("iteratorHashSet: "+(end-start));
  21. }
  22. privatestaticvoid foreachHashSet(HashSet set){
  23. long start =System.currentTimeMillis();
  24. String[] arr =(String[])set.toArray(newString[0]);
  25. for(String str:arr)
  26. System.out.print(str);
  27. long end =System.currentTimeMillis();
  28. System.out.println();
  29. System.out.println("foreachHashSet: "+(end-start));
  30. }
  31. }
在iteratorHashSet中我們通過Set的iterator獲取迭代器,在foreachHashSet中我們使用toArray方法把Set轉換成陣列。
  1. iteratorHashSet:467
  2. foreachHashSet:403
兩次遍歷執行時間其實相差不大。