Java——(三)Collection之Set集合、HashSet類

來源:互聯網
上載者:User

標籤:

------Java培訓、Android培訓、iOS培訓、.Net培訓、期待與您交流! -------

一、Set集合

  Set集合不允許包含相同的元素,如果試圖把兩個相同的元素加入同一個Set集合中,則添加

操作失敗,add方法返回false,而新元素不會被加入。

  Set判斷兩對象相同不是使用==運算子,而是根據equals方法。也就是說,只要兩個對象用

equals方法比較返回true,Ser就不會接受這兩個對象;反之,只要兩個對象用equals方法比較

返回false,SEt就會接受這兩個對象(甚至這兩個對象是同一個對象,Set也可把它們當成兩個對

象出來)。下面是使用普通Set的樣本程式。

 

 1 import java.util.HashSet; 2 import java.util.Set; 3  4  5 public class SetTest { 6  7     public static void main(String[] args) { 8         Set names = new HashSet<>(); 9         //添加一個字串對象10         names.add(new String("暨雪"));11         //再次添加一個字串對象12         //因為兩個字串對象通過equals方法比較相等13         //所以添加失敗,返回false14         boolean reasult = names.add(new String("暨雪"));15         //從下面輸出看到集合只有一個元素16         System.out.println(reasult + "-->" + names);17     }18 19 }

 

運行結果:

false-->[暨雪]

  從上面程式中可以看出,names集合兩次添加的字串對象明顯不是同一對象(因為兩次都調

用了new關鍵字來建立字串對象),這兩個字串對象使用==運算子判斷肯定返回false,但通過

equals方法比較將返回true,所以添加失敗。最後結果輸出只有一個元素。

 

 1.HashSet類

HashSet是Set介面的典型實現,大多數時候使用Set集合是就是使用這個實作類別。HashSet按Hash

演算法來儲存集合中的元素,因此具有很好的存取和尋找效能。

  HashSet具有以下特點:

  1)不能保證元素的排序次序,順序有可能發生變化。

  2)HashSet不是同步的,如果多線程同時訪問一個HashSet,假設有兩個或兩個以上線程同時

修改了HashSet集合時,則必須通過代碼來保證其同步。

  3)集合元素值可以是null。

  HashSet集合判斷兩個以上相等的標準是兩個對象通過equals()方法比較相等,並且兩個對象的

hashCode()方法傳回值也相等。

下面程式分別提供了三個類A、B和C,它們分別重寫了equals()、hashCode()兩個方法的一個或全部

,通過此程式可以看到HashSet判斷集合元素相同的標準。

 1 import java.util.HashSet; 2  3  4 public class HashSetTest { 5     //類A的equals方法總是返回true,但沒有重寫hashCode方法 6     static class A { 7         @Override 8         public boolean equals(Object o) { 9             return true;10         }11     }12     //類B的hashCode總是返回1,但沒有重寫equals方法13     static class B {14         @Override15         public int hashCode() {16             return 1;17         }18     }19     //類C重寫了hashCode方法和equals方法20     static class C {21         @Override22         public int hashCode() {23             return 2;24         }25         @Override26         public boolean equals(Object obj) {27             return true;28         }29     }30 31     public static void main(String[] args) {32 33         HashSet names = new HashSet<>();34         names.add(new A());35         names.add(new A());36         names.add(new B());37         names.add(new B());38         names.add(new C());39         names.add(new C());40         41         System.out.println(names);42     }43 44 }

運行結果:

[[email protected], [email protected], [email protected], [email protected], [email protected]]

從上面程式可以看出,即使兩個A對象通過equals()方法比較返回true,但HashSet依然把它們當成

兩個對象;即使兩個B對象的hashCode()返回相同值(都是1),但HashSet依然把它們當成同一個

對象。

注意:

 當把一個對象放入HashSet中時,如果需要重寫該方法對應類的equals()方法,則也應該重寫

hashCode()方法。其規則是:如果兩個對象通過equals()方法比較返回true,這兩個對象的hashCode

()值也應該相同。

  重寫hashCode()方法的基本規則:

  1)在程式運行中,同一對象多次調用hashCode()方法應該返回相同的值。

  2)當兩個對象通過equals()方法比較返回true時,這兩個對象的hashCode()方法應返回相等的值。

  3)對象中用作equals()方法比較標準的Filed,都應該用計算hashCode值。

hashCode傳回值的計算:

return f1.hashCode() + (int) f2;

為了避免直接相加產生偶然相等(兩個對象f1、f2Field並不相等,但他們的和恰好相等),

可以通過為個Field乘以任意一個質數後在相加。

return f1.hashCode() * 17 + (int) f2 * 13;

   如果向HashSet中添加一個可變對象後,後面出現修改了該可變對象的Field,則可能導致

它與集合中的其他元素相同(即兩個對象通過equals()方法比較返回true,兩個對象的

hashCode()值也相等)。這就有可能導致HashSet中包含兩個相同的對象。下面程式示範了這

種情況。

 1 import java.util.HashSet; 2 import java.util.Iterator; 3  4 class R { 5     int count; 6     public R (int count){ 7         this.count = count; 8     } 9     @Override10     public String toString() {11         12         return "R[count:" + count + "]";13     }14     @Override15     public boolean equals(Object obj) {16         17         if (this == obj) {18             return true;19         }20         if (obj != null && obj.getClass() == R.class) {21             R r = (R) obj;22             if (r.count == this.count) {23                 return true;24             }25         }26         return false;27     }28     @Override29     public int hashCode() {30         31         return this.count;32     }33 }34 public class HashSetTest2 {35 36     public static void main(String[] args) {37 38         HashSet hs = new HashSet<>();39         hs.add(new R(5));40         hs.add(new R(-3));41         hs.add(new R(9));42         hs.add(new R(-2));43         //列印HashSet集合,集合沒有重複44         System.out.println(hs);45         //取出第一個元素46         Iterator it = hs.iterator();47         R first = (R) it.next();48         //為第一個元素的count執行個體變數賦值49         first.count = -3;50         //再次輸出HashSet集合,集合元素有重複元素51         System.out.println(hs);52         //刪除count為-3的R對象53         hs.remove(new R(-3));54         System.out.println(hs);55         System.out.println("hs是否包count為-3的R對象?" + hs.contains(new R(-3)));56         System.out.println("hs是否包count為5的R對象?" + hs.contains(new R(5)));57         System.out.println("hs是否包count為9的R對象?" + hs.contains(new R(9)));58     }59 60 }

運行結果:

[R[count:5], R[count:9], R[count:-3], R[count:-2]][R[count:-3], R[count:9], R[count:-3], R[count:-2]][R[count:-3], R[count:9], R[count:-2]]hs是否包count為-3的R對象?falsehs是否包count為5的R對象?falsehs是否包count為9的R對象?true

  上面程式中的first.count = -3;因為改變了HashSet集合中第一個R對象的count執行個體變數

的值,這將導致該R對象與集合中的其他對象相同。當試圖刪除count = -3的R對象時,HashSet

會計算出該對象的hashCode值,從而找出該對象在集合中儲存位置,然後把此處的對象與count

為-3的R對象通過equals()方法進行比較,如果相等則刪除該對象——HashSet只有第三元素才

滿足該條件(第一個元素實際上儲存在count為5的R對象對應的位置),所以第三個元素被刪除

。至於第一個count為-3的R對象,他保持在count為5的R對象對應的位置,但是用equals()方法

拿它和count為5的R對象比較時有返回false——這將導致HashSet不可能準確訪問該元素。

  

 

Java——(三)Collection之Set集合、HashSet類

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在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.