1. 程式人生 > >hashcode與equals的緣分

hashcode與equals的緣分

get ava tab ted strong 修改 程序員 else 對稱性

重寫equals方法必須重寫hashCode方法?

看jdk的api怎麽說?

hashCode

public int hashCode()
返回該對象的哈希碼值。支持此方法是為了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
hashCode 的常規協定是: 在 Java 應用程序執行期間,在對同一對象多次調用 hashCode 方法時,必須一致地返回相同的整數,前提是將對象進行 equals 比較時所用的信息沒有被修改。
從某一應用程序的一次執行到同一應用程序的另一次執行,該整數無需保持一致。 如果根據 equals(Object) 方法,兩個對象是相等的,那麽對這兩個對象中的每個對象調用 hashCode 方法都必須生成相同的整數結果。
如果根據 equals(java.lang.Object) 方法,兩個對象不相等,那麽對這兩個對象中的任一對象上調用 hashCode 方法不要求一定生成不同的整數結果。
但是,程序員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。 實際上,由 Object 類定義的 hashCode 方法確實會針對不同的對象返回不同的整數。
(這一般是通過將該對象的內部地址轉換成一個整數來實現的,但是 JavaTM 編程語言不需要這種實現技巧。) equals
public boolean equals(Object obj) 指示其他某個對象是否與此對象“相等”。 equals 方法在非空對象引用上實現相等關系:
自反性:對於任何非空引用值 x,x.equals(x) 都應返回
true。 對稱性:對於任何非空引用值 x 和 y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true。 傳遞性:對於任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,並且 y.equals(z) 返回 true,那麽 x.equals(z) 應返回 true。 一致性:對於任何非空引用值 x 和 y,多次調用 x.equals(y) 始終返回 true 或始終返回 false,前提是對象上 equals 比較中所用的信息沒有被修改。 對於任何非空引用值 x,x.equals(
null) 都應返回 false
Object 類的 equals 方法實現對象上差別可能性最大的相等關系;
即,對於任何非空引用值 x 和 y,當且僅當 x 和 y 引用同一個對象時,此方法才返回
true(x == y 具有值 true)。 註意:當此方法被重寫時,通常有必要重寫 hashCode 方法,以維護 hashCode 方法的常規協定,該協定聲明相等對象必須具有相等的哈希碼。
如果不重寫equals,那麽比較的將是對象的引用是否指向同一塊內存地址,重寫之後目的是為了比較兩個對象的value值是否相等。特別指出利用equals比較八大包裝對象
(如int,float等)和String類(因為該類已重寫了equals和hashcode方法)對象時,默認比較的是值,在比較其它自定義對象時都是比較的引用地址
hashcode是用於散列數據的快速存取,如利用HashSet/HashMap/Hashtable類來存儲數據時,都是根據存儲對象的hashcode值來進行判斷是否相同的。
這樣如果我們對一個對象重寫了euqals,意思是只要對象的成員變量值都相等那麽euqals就等於true,但不重寫hashcode,那麽我們再new一個新的對象,
當原對象.equals(新對象)等於true時,兩者的hashcode卻是不一樣的,由此將產生了理解的不一致
如在存儲散列集合時(如Set類),將會存儲了兩個值一樣的對象,
導致混淆,因此,就也需要重寫hashcode()
舉個例子:(轉載自:
http://www.jianshu.com/p/75d9c2c3d0c1
public class HashMapTest {
    private Integer a;

    public HashMapTest(int a) {
        this.a = a;
    }

    public static void main(String[] args) {
        Map<HashMapTest, Integer> map = new HashMap<HashMapTest, Integer>();
        HashMapTest instance = new HashMapTest(1);
        HashMapTest newInstance = new HashMapTest(1);
        map.put(instance, 1);
        map.put(newInstance, 2);
        Integer value = map.get(instance);
        System.out.println("instance value:"+value);
        Integer value1 = map.get(newInstance);
        System.out.println("newInstance value:"+value1);

    }

    public boolean equals(Object o) {
        if(o == this) {
            return true;
        } else if(!(o instanceof HashMapTest)) {
            return false;
        } else {
            HashMapTest other = (HashMapTest)o;
            if(!other.canEqual(this)) {
                return false;
            } else {
                Integer this$data = this.getA();
                Integer other$data = other.getA();
                if(this$data == null) {
                    if(other$data != null) {
                        return false;
                    }
                } else if(!this$data.equals(other$data)) {
                    return false;
                }

                return true;
            }
        }
    }
    protected boolean canEqual(Object other) {
        return other instanceof HashMapTest;
    }

    public void setA(Integer a) {
        this.a = a;
    }

    public Integer getA() {
        return a;
    }
}
//運行結果:
//instance value:1
//newInstance value:2


??你會發現,不對呀?同樣的一個對象,為什麽在map中存了2份,map的key值不是不能重復的麽?沒錯,它就是存的2份,只不過在它看來,這2個的key是不一樣的,因為他們的哈希碼就是不一樣的,可以自己測試下,上面打印的hash碼確實不一樣。那怎麽辦?只有重寫hashCode()方法,更改後的代碼如下:
public class HashMapTest {
    private Integer a;

    public HashMapTest(int a) {
        this.a = a;
    }

    public static void main(String[] args) {
        Map<HashMapTest, Integer> map = new HashMap<HashMapTest, Integer>();
        HashMapTest instance = new HashMapTest(1);
        System.out.println("instance.hashcode:" + instance.hashCode());
        HashMapTest newInstance = new HashMapTest(1);
        System.out.println("newInstance.hashcode:" + newInstance.hashCode());
        map.put(instance, 1);
        map.put(newInstance, 2);
        Integer value = map.get(instance);
        System.out.println("instance value:"+value);
        Integer value1 = map.get(newInstance);
        System.out.println("newInstance value:"+value1);

    }

    public boolean equals(Object o) {
        if(o == this) {
            return true;
        } else if(!(o instanceof HashMapTest)) {
            return false;
        } else {
            HashMapTest other = (HashMapTest)o;
            if(!other.canEqual(this)) {
                return false;
            } else {
                Integer this$data = this.getA();
                Integer other$data = other.getA();
                if(this$data == null) {
                    if(other$data != null) {
                        return false;
                    }
                } else if(!this$data.equals(other$data)) {
                    return false;
                }

                return true;
            }
        }
    }
    protected boolean canEqual(Object other) {
        return other instanceof HashMapTest;
    }

    public void setA(Integer a) {
        this.a = a;
    }

    public Integer getA() {
        return a;
    }

    public int hashCode() {
        boolean PRIME = true;
        byte result = 1;
        Integer $data = this.getA();
        int result1 = result * 59 + ($data == null?43:$data.hashCode());
        return result1;
    }
}
//運行結果:
//instance.hashcode:60
//newInstance.hashcode:60
//instance value:2
//newInstance value:2

 

hashcode與equals的緣分