java中hashCode和equals什么關系,hashCode到底怎么用的

Object類的hashCode的用法:(新手一定要忽略本節(jié),否則會很慘)
馬克-to-win:hashCode方法主要是Sun編寫的一些數據結構比如Hashtable的hash算法中用到。因為hash很快,所以你往 Hashtable里放東西的時候,他先比一下,里面有沒有現有的東西的hashCode和你一樣,如果都不一樣,證明是新的,就不再運行equals方法了,直接放進Hashtable里了,很快。如果放的時候,Hashtable里面現有的某東西的hashCode和他一樣,他再運行一下 equals,如不一樣,則證明是新的,可以放入。equals也一樣,證明確實是一樣的,不讓放入Hashtable。另外,Object的hashCode方法(Sun公司編的)是返回對象的內部地址。equals原始方法判斷兩個Object是否a==b,內存地址是否等(以下摘自sun的文檔:As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
馬克- to-win:馬克 java社區(qū):防盜版實名手機尾號: 73203。



最后,補充一點,Sun公司Object的equals方法文檔上指明:for any non-null reference values x and y, this method returns true if and only if x and y refer to the same object (x == y has the value true). Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes. 假如兩個對象的equals返回值一樣,hashcode返回值必須一樣。但是反過來hashcode等,未必equals等,這就是剛才我們說先判斷 hashcode是否等,即使等,也要再運行equals,判斷是否真的等。馬克-to-win:從現實看,按照這邏輯編程,是效率最高,最合理的,本文這里的例子之所以沒按照這條,只是為了說明本文所講的問題。




例2.1.2.1(hashCode都不一樣)---本章源碼

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被調用");
/*下句話,假如不是CompanyMark_to_win類型,馬克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉型
        return name.equals(c.name);//這個equals是String的方法
    }
    public int hashCode() {
        System.out.println("hashCode 被調用 "+super.hashCode());
        return super.hashCode();
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//這個equals會調用子類CompanyMark_to_win的方法,馬克-to-win:
        HashSet set = new HashSet();
set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一樣嗎?"+ht.containsKey(c2));
    }
}

輸出結果:

equals被調用
c1.equals(c2): true
hashCode 被調用 31168322
hashCode 被調用 17225372
set size:2
hashCode 被調用 31168322
hashCode 被調用 17225372
一樣嗎?false




結果分析:

當把c1和c2放入HashSet和Hashtable時,每次放一個對象,就會調用一次HashCode方法。而這里的hashCode是父類 Object的,所以返回內部地址,不一樣。于是HashSet加進去了,size為2,Hashtable也認為c1和c2不一樣。HashSet和Hashtable通過 hashCode方法認為c1和c2不一樣,即使equals說一樣都沒用,因為hashcode不一樣,就不運行equals了。

例2.1.2.1_b(上例的簡版,省略了hashCode方法,直接用父類的)---本章源碼

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被調用");
/*下句話,假如不是CompanyMark_to_win類型,馬克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉型
        return name.equals(c.name);//這個equals是String的方法
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//這個equals會調用子類CompanyMark_to_win的方法,馬克-to-win:
        HashSet set = new HashSet();
        set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一樣嗎?"+ht.containsKey(c2));
    }
}

輸出結果:

equals被調用
c1.equals(c2): true
set size:2
一樣嗎?false




例2.1.2.2(hashcode一樣,equals不一樣。)---本章源碼

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被調用");
/*下句話,假如不是CompanyMark_to_win類型,馬克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉型
        return name.equals(c.name);//這個equals是String的方法
    }
    public int hashCode() {
        System.out.println("hashCode 被調用 ");
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc1");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//這個equals會調用子類CompanyMark_to_win的方法,馬克-to-win:
        HashSet set = new HashSet();
        set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, c1);
        System.out.println("一樣嗎?"+ht.containsKey(c2));   
    }
}

輸出結果:

equals被調用
c1.equals(c2): false
hashCode 被調用
hashCode 被調用
equals被調用
set size:2
hashCode 被調用
hashCode 被調用
equals被調用
一樣嗎?false


結果分析:本例hashcode一樣,所以equals方法被調用,equals返回值不一樣,所以HashSet和Hashtable都認為c1和c2是不同的對象,都接受了, size等于2。




例2.1.2.2(hashcode一樣,equals也一樣。)---本章源碼

import java.util.*;
class CompanyMark_to_win {
    private String name;
    CompanyMark_to_win(String name) {
        this.name = name;
    }
    public boolean equals(Object o) {
        System.out.println("equals被調用");
/*下句話,假如不是CompanyMark_to_win類型,馬克-to-win:就返回假*/    
        if (!(o instanceof CompanyMark_to_win)) return false;
        CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉型
        return name.equals(c.name);//這個equals是String的方法
    }
    public int hashCode() {
        System.out.println("hashCode 被調用 ");
        return 5;
    }
}
public class Test {
    public static void main(String[] args) {
        CompanyMark_to_win c1 = new CompanyMark_to_win("Abc");
        CompanyMark_to_win c2 = new CompanyMark_to_win("Abc");
        System.out.println("c1.equals(c2): " + c1.equals(c2));//這個equals會調用子類CompanyMark_to_win的方法,馬克-to-win:
        HashSet set = new HashSet();
        set.add(c1);
        set.add(c2);
        System.out.println("set size:"+ set.size());
        Hashtable ht = new Hashtable();
        ht.put(c1, 1);
        System.out.println("一樣嗎?"+ht.containsKey(c2));
    }
}

輸出結果:
equals被調用
c1.equals(c2): true
hashCode 被調用
hashCode 被調用
equals被調用
set size:1
hashCode 被調用
hashCode 被調用
equals被調用
一樣嗎?true

結果分析:本例hashcode一樣,所以equals方法被調用,equals返回值一樣,所以HashSet和Hashtable都認為c1和c2是相同的對象,只接受了1個, size等于1。