java hashset去重原理__Java

來源:互聯網
上載者:User
Java中的set是一個不包含重複元素的集合,確切地說,是不包含e1.equals(e2)的元素對。Set中允許添加null。Set不能保證集合裡元素的順序。

在往set中添加元素時,如果指定元素不存在,則添加成功。也就是說,如果set中不存在(e==null ? e1==null : e.queals(e1))的元素e1,則e1能添加到set中。


下面以set的一個實作類別HashSet為例,簡單介紹一下set不重複實現的原理:

[java] view plain copy print ? package com.darren.test.overide;      public class CustomString {       private String value;          public CustomString() {           this(“”);       }          public CustomString(String value) {           this.value = value;       }   }  

package com.darren.test.overide;public class CustomString {    private String value;    public CustomString() {        this("");    }    public CustomString(String value) {        this.value = value;    }}

[java] view plain copy print ? package com.darren.test.overide;      import java.util.HashSet;   import java.util.Set;      public class HashSetTest {       public static void main(String[] args) {           String a = new String(“A”);           String b = new String(“A”);                      CustomString c = new CustomString(“B”);           CustomString d = new CustomString(“B”);                      System.out.println(”a.equals(b) == ” + a.equals(b));           System.out.println(”c.equals(d) == ” + c.equals(d));                      Set<Object> set = new HashSet<Object>();           set.add(a);           set.add(b);           set.add(c);           set.add(d);                      System.out.println(”set.size() == ” + set.size());                      for (Object object : set) {               System.out.println(object);           }       }   }  
package com.darren.test.overide;import java.util.HashSet;import java.util.Set;public class HashSetTest {    public static void main(String[] args) {        String a = new String("A");        String b = new String("A");        CustomString c = new CustomString("B");        CustomString d = new CustomString("B");        System.out.println("a.equals(b) == " + a.equals(b));        System.out.println("c.equals(d) == " + c.equals(d));        Set<Object> set = new HashSet<Object>();        set.add(a);        set.add(b);        set.add(c);        set.add(d);        System.out.println("set.size() == " + set.size());        for (Object object : set) {            System.out.println(object);        }    }}

運行結果如下:

[plain] view plain copy print ? a.equals(b) == true   c.equals(d) == false   set.size() == 3   com.darren.test.overide.CustomString@2c39d2   A   com.darren.test.overide.CustomString@5795ce  

a.equals(b) == truec.equals(d) == falseset.size() == 3com.darren.test.overide.CustomString@2c39d2Acom.darren.test.overide.CustomString@5795ce


也許你已經看出關鍵來了,沒錯就是equals方法。這麼說還是不恰當,準確的說應該是equals和hashcode方法。為什麼這麼說呢,讓我們改一改CustomString類在進行測試:

[java] view plain copy print ? package com.darren.test.overide;      public class CustomString {       private String value;          public CustomString() {           this(“”);       }          public CustomString(String value) {           this.value = value;       }          @Override       public boolean equals(Object obj) {           if (this == obj) {                              return true;           } else if (obj instanceof CustomString) {               CustomString customString = (CustomString) obj;                              return customString.value.equals(value);           } else {                              return false;           }       }   }  

package com.darren.test.overide;public class CustomString {    private String value;    public CustomString() {        this("");    }    public CustomString(String value) {        this.value = value;    }    @Override    public boolean equals(Object obj) {        if (this == obj) {            return true;        } else if (obj instanceof CustomString) {            CustomString customString = (CustomString) obj;            return customString.value.equals(value);        } else {            return false;        }    }}

測試結果:

[html] view plain copy print ? a.equals(b) == true   c.equals(d) == true   set.size() == 3   com.darren.test.overide.CustomString@12504e0   A   com.darren.test.overide.CustomString@1630eb6  

a.equals(b) == truec.equals(d) == trueset.size() == 3com.darren.test.overide.CustomString@12504e0Acom.darren.test.overide.CustomString@1630eb6

這次的equals傳回值都為true,但是set的size還是3

讓我們繼續改

[java] view plain copy print ? package com.darren.test.overide;      public class CustomString {       private String value;          public CustomString() {           this(“”);       }          public CustomString(String value) {           this.value = value;       }          @Override       public int hashCode() {           // return super.hashCode();           return 1;       }   }  

package com.darren.test.overide;public class CustomString {    private String value;    public CustomString() {        this("");    }    public CustomString(String value) {        this.value = value;    }    @Override    public int hashCode() {        // return super.hashCode();        return 1;    }}

再看結果:

[plain] view plain copy print ? a.equals(b) == true   c.equals(d) == false   set.size() == 3   com.darren.test.overide.CustomString@1   com.darren.test.overide.CustomString@1   A  

a.equals(b) == truec.equals(d) == falseset.size() == 3com.darren.test.overide.CustomString@1com.darren.test.overide.CustomString@1A


只重寫hashCode方法,不重寫equals方法也不行

最後再改一改

[java] view plain copy print ? package com.darren.test.overide;      public class CustomString {       private String value;          public CustomString() {           this(“”);       }          public CustomString(String value) {           this.value = value;       }          @Override       public boolean equals(Object obj) {           if (this == obj) {                  return true;           } else if (obj instanceof CustomString) {               CustomString customString = (CustomString) obj;                  return customString.value.equals(value);           } else {                  return false;           }       }          @Override       public int hashCode() {           // return super.hashCode();           return 1;       }   }  

package com.darren.test.overide;public class CustomString {    private String value;    public CustomString() {        this("");    }    public CustomString(String value) {        this.value = value;    }    @Override    public boolean equals(Object obj) {        if (this == obj) {            return true;        } else if (obj instanceof CustomString) {            CustomString customString = (CustomString) obj;            return customString.value.equals(value);        } else {            return false;        }    }    @Override    public int hashCode() {        // return super.hashCode();        return 1;    }}

最後結果:

[plain] view plain copy print ? a.equals(b) == true   c.equals(d) == true   set.size() == 2   com.darren.test.overide.CustomString@1   A  

a.equals(b) == truec.equals(d) == trueset.size() == 2com.darren.test.overide.CustomString@1A


可以了,證明需要重寫equals方法和hashCode方法,來看原理:

java.lnag.Object中對hashCode的約定:

1. 在一個應用程式執行期間,如果一個對象的equals方法做比較所用到的資訊沒有被修改的話,則對該對象調用hashCode方法多次,它必須始終如一地返回同一個整數。

2. 如果兩個對象根據equals(Object o)方法是相等的,則調用這兩個對象中任一對象的hashCode方法必須產生相同的整數結果。

3. 如果兩個對象根據equals(Object o)方法是不相等的,則調用這兩個對象中任一個對象的hashCode方法,不要求產生不同的整數結果。但如果能不同,則可能提高散列表的效能。


在HashSet中,基本的操作都是有HashMap底層實現的,因為HashSet底層是用HashMap儲存資料的。當向HashSet中添加元素的時候,首先計算元素的hashcode值,然後用這個(元素的hashcode)%(HashMap集合的大小)+1計算出這個元素的儲存位置,如果這個位置位空,就將元素添加進去;如果不為空白,則用equals方法比較元素是否相等,相等就不添加,否則找一個空位添加。

如下是HashSet的部分源碼:

[java] view plain copy print ? package java.util;      public class HashSet<E> extends AbstractSet<E>        implements Set<E>, Cloneable, java.io.Serializable   {       static final long serialVersionUID = -5024744406713321676L;             // 底層使用HashMap來儲存HashSet中所有元素。          private transient HashMap<E,Object> map;                // 定義一個虛擬Object對象作為HashMap的value,將此對象定義為static final。          private static final Object PRESENT = new Object();             /**        * 預設的無參構造器,構造一個空的HashSet。        *         * 實際底層會初始化一個空的HashMap,並使用預設初始容量為16和載入因子0.75。        */          public HashSet() {           map = new HashMap<E,Object>();       }          

聯繫我們

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