1. 程式人生 > >關於HashCode和equals方法在HashSet中的使用

關於HashCode和equals方法在HashSet中的使用

Object類是類層次結構的根類,故所有的類都是先該類的方法,其中HashCode()和equals()方法也是該類的方法。
1.HashCode()方法
Object類中HashCode()方法實現如下:

public  native  int  hashCode();

返回:該物件的雜湊值,可提高雜湊表的效能。
HashCode:
1.同一物件多次呼叫HashCode()方法,返回一直的整數,從某一程式的依次執行到同一程式的另一次執行,該整數無需保持一致;
2.使用equals(Object)方法兩個物件是相等的,那麼兩個物件返回的Hash值完全一致;
3. 使用equals(Object)方法兩個物件不相等,其返回的Hash值有可能相等。
下面摘錄API中String的HashCode()方法及相關屬性:

private final char value[];
    private int hash; // Default to 0
    public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;

            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return
h; }

給定一個字串,相當於在執行構造方法:

public String() {
        this.value = new char[0];
}

此時,value值已經給定,此構造方法下value.length=0,顯然hash=h=0(預設值為0,也就是空字串),重在理解過程,雜湊演算法看API文件就好。

String s = new String();
System.out.Println(s.HashCode());
結果:0

2.equals()方法
Object類中equals()方法的實現如下:

public boolean equals(Object obj) {
        return
(this == obj); }

指示其他某個物件是否與此物件引數相同,相同返回true,反之。equals()方法在非空物件引用(obj)上實現相等關係,對於任何非空引用值x,x.equals(null)都應返回false。String等類都會覆蓋Object類中的方法。
3.類HashSet
HashSet是Set介面的一個實現類,不能重複新增物件值,這個過程主要由Hash值和物件的equals()方法判斷,使用add()方法新增某種型別物件
//測試類

package com.test;
//測試類,該類重寫了從Object繼承而來的HashCode()和equals()方法
public class StudentTest {
    private String name;
    private int age;
    public StudentTest(){}
    public StudentTest(String name, int age){
        this.name = name;
        this.age = age;
    }
    public String getName(){
        return name;
    }
    public void setName(String name){
        this.name = name;
    }
    public int getAge(){
        return age;
    }
    public void setAge(int age){
        this.age = age;
    }
}

//HashSet類

package com.test;

import java.util.HashSet;
import java.util.Set;

public class SetDemo {
    public static void main(String[] args) {
        Set<StudentTest> set1 = new HashSet<>();
        StudentTest s1 = new StudentTest("manu",10);
        StudentTest s2 = new StudentTest("manu",10);
//      set1.add(null);//此處null元素可以使用
        set1.add(s1);
        System.out.println(s1.hashCode());
        set1.add(s2);
        System.out.println(s2.hashCode());
        System.out.println(set1.size());    
    }
}
執行結果:
794284386
779325750
2

上面s1、s2是兩個物件,每一次新增物件是hash值都不同,故該物件可以新增到HashSet中,其size=2,上面涉及到一個問題,某個物件的屬性一致,如果不想將屬性一致的物件再一次新增進去,則必須重寫StudentTest類的HashCode()方法和equals()方法,經過重寫兩者hash相同,在用equals方法來驗證,返回true,表示兩個物件重複,反之。程式碼如下:

@Override
    public int hashCode() {
        System.out.println("hashCode");//用於測試
        final int prime = 31;
        int result = 1;
        result = prime * result + age;
        result = prime * result + ((name == null) ? 0 : name.hashCode());
        return result;
    }
    @Override
    public boolean equals(Object obj) {
        System.out.println("equals");//用於測試
        if (this == obj)
            return true;
        if (obj == null)
            return false;
        if (getClass() != obj.getClass())
            return false;
        StudentTest other = (StudentTest) obj;
        if (age != other.age)
            return false;
        if (name == null) {
            if (other.name != null)
                return false;
        } else if (!name.equals(other.name))
            return false;
        return true;
    }

此時執行結果如下:

hashCode
hashCode
3345234
hashCode
equals
hashCode
3345234
1

兩者不同的物件,屬性值一致,但不能新增到HashSet中,注意需求的變化。
在HashSet中新增元素時,若hash值不一致,則可以新增;若hash值一致,呼叫equals方法看物件是否相同,不同(false)則可以新增。注意equals判斷,某兩個物件不同,hash值可能相同,上述示例中hash值相同,但s1和s2是兩個不同物件。
這裡寫圖片描述