日韩黑丝制服一区视频播放|日韩欧美人妻丝袜视频在线观看|九九影院一级蜜桃|亚洲中文在线导航|青草草视频在线观看|婷婷五月色伊人网站|日本一区二区在线|国产AV一二三四区毛片|正在播放久草视频|亚洲色图精品一区

分享

java中HashSet詳解

對(duì)于 HashSet 而言,它是基于 HashMap 實(shí)現(xiàn)的,HashSet 底層采用 HashMap 來保存所有元素,因此 HashSet 的實(shí)現(xiàn)比較簡(jiǎn)單,查看 HashSet 的源代碼,可以看到如下代碼:

Java代碼  收藏代碼
  1. public class HashSet<E>   
  2.  extends AbstractSet<E>   
  3.  implements Set<E>, Cloneable, java.io.Serializable   
  4. {   
  5.  // 使用 HashMap 的 key 保存 HashSet 中所有元素  
  6.  private transient HashMap<E,Object> map;   
  7.  // 定義一個(gè)虛擬的 Object 對(duì)象作為 HashMap 的 value   
  8.  private static final Object PRESENT = new Object();   
  9.  ...   
  10.  // 初始化 HashSet,底層會(huì)初始化一個(gè) HashMap   
  11.  public HashSet()   
  12.  {   
  13.      map = new HashMap<E,Object>();   
  14.  }   
  15.  // 以指定的 initialCapacity、loadFactor 創(chuàng)建 HashSet   
  16.  // 其實(shí)就是以相應(yīng)的參數(shù)創(chuàng)建 HashMap   
  17.  public HashSet(int initialCapacity, float loadFactor)   
  18.  {   
  19.      map = new HashMap<E,Object>(initialCapacity, loadFactor);   
  20.  }   
  21.  public HashSet(int initialCapacity)   
  22.  {   
  23.      map = new HashMap<E,Object>(initialCapacity);   
  24.  }   
  25.  HashSet(int initialCapacity, float loadFactor, boolean dummy)   
  26.  {   
  27.      map = new LinkedHashMap<E,Object>(initialCapacity   
  28.          , loadFactor);   
  29.  }   
  30.  // 調(diào)用 map 的 keySet 來返回所有的 key   
  31.  public Iterator<E> iterator()   
  32.  {   
  33.      return map.keySet().iterator();   
  34.  }   
  35.  // 調(diào)用 HashMap 的 size() 方法返回 Entry 的數(shù)量,就得到該 Set 里元素的個(gè)數(shù)  
  36.  public int size()   
  37.  {   
  38.      return map.size();   
  39.  }   
  40.  // 調(diào)用 HashMap 的 isEmpty() 判斷該 HashSet 是否為空,  
  41.  // 當(dāng) HashMap 為空時(shí),對(duì)應(yīng)的 HashSet 也為空  
  42.  public boolean isEmpty()   
  43.  {   
  44.      return map.isEmpty();   
  45.  }   
  46.  // 調(diào)用 HashMap 的 containsKey 判斷是否包含指定 key   
  47.  //HashSet 的所有元素就是通過 HashMap 的 key 來保存的  
  48.  public boolean contains(Object o)   
  49.  {   
  50.      return map.containsKey(o);   
  51.  }   
  52.  // 將指定元素放入 HashSet 中,也就是將該元素作為 key 放入 HashMap   
  53.  public boolean add(E e)   
  54.  {   
  55.      return map.put(e, PRESENT) == null;   
  56.  }   
  57.  // 調(diào)用 HashMap 的 remove 方法刪除指定 Entry,也就刪除了 HashSet 中對(duì)應(yīng)的元素  
  58.  public boolean remove(Object o)   
  59.  {   
  60.      return map.remove(o)==PRESENT;   
  61.  }   
  62.  // 調(diào)用 Map 的 clear 方法清空所有 Entry,也就清空了 HashSet 中所有元素  
  63.  public void clear()   
  64.  {   
  65.      map.clear();   
  66.  }   
  67.  ...   
  68. }   



由上面源程序可以看出,HashSet 的實(shí)現(xiàn)其實(shí)非常簡(jiǎn)單,它只是封裝了一個(gè) HashMap 對(duì)象來存儲(chǔ)所有的集合元素,所有放入 HashSet 中的集合元素實(shí)際上由 HashMap 的 key 來保存,而 HashMap 的 value 則存儲(chǔ)了一個(gè) PRESENT,它是一個(gè)靜態(tài)的 Object 對(duì)象。

HashSet 的絕大部分方法都是通過調(diào)用 HashMap 的方法來實(shí)現(xiàn)的,因此 HashSet 和 HashMap 兩個(gè)集合在實(shí)現(xiàn)本質(zhì)上是相同的。
掌握上面理論知識(shí)之后,接下來看一個(gè)示例程序,測(cè)試一下自己是否真正掌握了 HashMap 和 HashSet 集合的功能。
Java代碼  收藏代碼
  1.  class Name  
  2. {  
  3.     private String first;   
  4.     private String last;   
  5.       
  6.     public Name(String first, String last)   
  7.     {   
  8.         this.first = first;   
  9.         this.last = last;   
  10.     }   
  11.   
  12.     public boolean equals(Object o)   
  13.     {   
  14.         if (this == o)   
  15.         {   
  16.             return true;   
  17.         }   
  18.           
  19.     if (o.getClass() == Name.class)   
  20.         {   
  21.             Name n = (Name)o;   
  22.             return n.first.equals(first)   
  23.                 && n.last.equals(last);   
  24.         }   
  25.         return false;   
  26.     }   
  27. }  
  28.   
  29. public class HashSetTest  
  30. {  
  31.     public static void main(String[] args)  
  32.     {   
  33.         Set<Name> s = new HashSet<Name>();  
  34.         s.add(new Name("abc""123"));  
  35.         System.out.println(  
  36.             s.contains(new Name("abc""123")));  
  37.     }  
  38. }   



上面程序中向 HashSet 里添加了一個(gè) new Name("abc", "123") 對(duì)象之后,立即通過程序判斷該 HashSet 是否包含一個(gè) new Name("abc", "123") 對(duì)象。粗看上去,很容易以為該程序會(huì)輸出 true。

實(shí)際運(yùn)行上面程序?qū)⒖吹匠绦蜉敵?false,這是因?yàn)?HashSet 判斷兩個(gè)對(duì)象相等的標(biāo)準(zhǔn)除了要求通過 equals() 方法比較返回 true 之外,還要求兩個(gè)對(duì)象的 hashCode() 返回值相等。而上面程序沒有重寫 Name 類的 hashCode() 方法,兩個(gè) Name 對(duì)象的 hashCode() 返回值并不相同,因此 HashSet 會(huì)把它們當(dāng)成 2 個(gè)對(duì)象處理,因此程序返回 false。

由此可見,當(dāng)我們?cè)噲D把某個(gè)類的對(duì)象當(dāng)成 HashMap 的 key,或試圖將這個(gè)類的對(duì)象放入 HashSet 中保存時(shí),重寫該類的 equals(Object obj) 方法和 hashCode() 方法很重要,而且這兩個(gè)方法的返回值必須保持一致:當(dāng)該類的兩個(gè)的 hashCode() 返回值相同時(shí),它們通過 equals() 方法比較也應(yīng)該返回 true。通常來說,所有參與計(jì)算 hashCode() 返回值的關(guān)鍵屬性,都應(yīng)該用于作為 equals() 比較的標(biāo)準(zhǔn)。
如下程序就正確重寫了 Name 類的 hashCode() 和 equals() 方法,程序如下:
Java代碼  收藏代碼
  1. class Name   
  2. {   
  3.     private String first;  
  4.     private String last;  
  5.     public Name(String first, String last)  
  6.     {   
  7.         this.first = first;   
  8.         this.last = last;   
  9.     }   
  10.     // 根據(jù) first 判斷兩個(gè) Name 是否相等  
  11.     public boolean equals(Object o)   
  12.     {   
  13.         if (this == o)   
  14.         {   
  15.             return true;   
  16.         }   
  17.         if (o.getClass() == Name.class)   
  18.         {   
  19.             Name n = (Name)o;   
  20.             return n.first.equals(first);   
  21.         }   
  22.         return false;   
  23.     }   
  24.        
  25.     // 根據(jù) first 計(jì)算 Name 對(duì)象的 hashCode() 返回值  
  26.     public int hashCode()   
  27.     {   
  28.         return first.hashCode();   
  29.     }  
  30.   
  31.     public String toString()   
  32.     {   
  33.         return "Name[first=" + first + ", last=" + last + "]";   
  34.     }   
  35.  }   
  36.    
  37.  public class HashSetTest2   
  38.  {   
  39.     public static void main(String[] args)   
  40.     {   
  41.         HashSet<Name> set = new HashSet<Name>();   
  42.         set.add(new Name("abc" , "123"));   
  43.         set.add(new Name("abc" , "456"));   
  44.         System.out.println(set);   
  45.     }   
  46. }  


上面程序中提供了一個(gè) Name 類,該 Name 類重寫了 equals() 和 toString() 兩個(gè)方法,這兩個(gè)方法都是根據(jù) Name 類的 first 實(shí)例變量來判斷的,當(dāng)兩個(gè) Name 對(duì)象的 first 實(shí)例變量相等時(shí),這兩個(gè) Name 對(duì)象的 hashCode() 返回值也相同,通過 equals() 比較也會(huì)返回 true。

程序主方法先將第一個(gè) Name 對(duì)象添加到 HashSet 中,該 Name 對(duì)象的 first 實(shí)例變量值為"abc",接著程序再次試圖將一個(gè) first 為"abc"的 Name 對(duì)象添加到 HashSet 中,很明顯,此時(shí)沒法將新的 Name 對(duì)象添加到該 HashSet 中,因?yàn)榇颂幵噲D添加的 Name 對(duì)象的 first 也是" abc",HashSet 會(huì)判斷此處新增的 Name 對(duì)象與原有的 Name 對(duì)象相同,因此無法添加進(jìn)入,程序在①號(hào)代碼處輸出 set 集合時(shí)將看到該集合里只包含一個(gè) Name 對(duì)象,就是第一個(gè)、last 為"123"的 Name 對(duì)象。

    本站是提供個(gè)人知識(shí)管理的網(wǎng)絡(luò)存儲(chǔ)空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點(diǎn)。請(qǐng)注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊一鍵舉報(bào)。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評(píng)論

    發(fā)表

    請(qǐng)遵守用戶 評(píng)論公約

    類似文章 更多