java中hashCode和equals什么關(guān)系,hashCode到底怎么用的
Object類(lèi)的hashCode的用法:(新手一定要忽略本節(jié),否則會(huì)很慘)
馬克-to-win:hashCode方法主要是Sun編寫(xiě)的一些數(shù)據(jù)結(jié)構(gòu)比如Hashtable的hash算法中用到。因?yàn)閔ash很快,所以你往 Hashtable里放東西的時(shí)候,他先比一下,里面有沒(méi)有現(xiàn)有的東西的hashCode和你一樣,如果都不一樣,證明是新的,就不再運(yùn)行equals方法了,直接放進(jìn)Hashtable里了,很快。如果放的時(shí)候,Hashtable里面現(xiàn)有的某東西的hashCode和他一樣,他再運(yùn)行一下 equals,如不一樣,則證明是新的,可以放入。equals也一樣,證明確實(shí)是一樣的,不讓放入Hashtable。另外,Object的hashCode方法(Sun公司編的)是返回對(duì)象的內(nèi)部地址。equals原始方法判斷兩個(gè)Object是否a==b,內(nèi)存地址是否等(以下摘自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ū):防盜版實(shí)名手機(jī)尾號(hào): 73203。
最后,補(bǔ)充一點(diǎn),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. 假如兩個(gè)對(duì)象的equals返回值一樣,hashcode返回值必須一樣。但是反過(guò)來(lái)hashcode等,未必equals等,這就是剛才我們說(shuō)先判斷 hashcode是否等,即使等,也要再運(yùn)行equals,判斷是否真的等。馬克-to-win:從現(xiàn)實(shí)看,按照這邏輯編程,是效率最高,最合理的,本文這里的例子之所以沒(méi)按照這條,只是為了說(shuō)明本文所講的問(wèn)題。
例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被調(diào)用");
/*下句話(huà),假如不是CompanyMark_to_win類(lèi)型,馬克-to-win:就返回假*/
if (!(o instanceof CompanyMark_to_win)) return false;
CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉(zhuǎn)型
return name.equals(c.name);//這個(gè)equals是String的方法
}
public int hashCode() {
System.out.println("hashCode 被調(diào)用 "+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));//這個(gè)equals會(huì)調(diào)用子類(lèi)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));
}
}
輸出結(jié)果:
equals被調(diào)用
c1.equals(c2): true
hashCode 被調(diào)用 31168322
hashCode 被調(diào)用 17225372
set size:2
hashCode 被調(diào)用 31168322
hashCode 被調(diào)用 17225372
一樣嗎?false
結(jié)果分析:
當(dāng)把c1和c2放入HashSet和Hashtable時(shí),每次放一個(gè)對(duì)象,就會(huì)調(diào)用一次HashCode方法。而這里的hashCode是父類(lèi) Object的,所以返回內(nèi)部地址,不一樣。于是HashSet加進(jìn)去了,size為2,Hashtable也認(rèn)為c1和c2不一樣。HashSet和Hashtable通過(guò) hashCode方法認(rèn)為c1和c2不一樣,即使equals說(shuō)一樣都沒(méi)用,因?yàn)閔ashcode不一樣,就不運(yùn)行equals了。
例2.1.2.1_b(上例的簡(jiǎn)版,省略了hashCode方法,直接用父類(lèi)的)---本章源碼
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被調(diào)用");
/*下句話(huà),假如不是CompanyMark_to_win類(lèi)型,馬克-to-win:就返回假*/
if (!(o instanceof CompanyMark_to_win)) return false;
CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉(zhuǎn)型
return name.equals(c.name);//這個(gè)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));//這個(gè)equals會(huì)調(diào)用子類(lèi)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));
}
}
輸出結(jié)果:
equals被調(diào)用
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被調(diào)用");
/*下句話(huà),假如不是CompanyMark_to_win類(lèi)型,馬克-to-win:就返回假*/
if (!(o instanceof CompanyMark_to_win)) return false;
CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉(zhuǎn)型
return name.equals(c.name);//這個(gè)equals是String的方法
}
public int hashCode() {
System.out.println("hashCode 被調(diào)用 ");
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));//這個(gè)equals會(huì)調(diào)用子類(lèi)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));
}
}
輸出結(jié)果:
equals被調(diào)用
c1.equals(c2): false
hashCode 被調(diào)用
hashCode 被調(diào)用
equals被調(diào)用
set size:2
hashCode 被調(diào)用
hashCode 被調(diào)用
equals被調(diào)用
一樣嗎?false
結(jié)果分析:本例hashcode一樣,所以equals方法被調(diào)用,equals返回值不一樣,所以HashSet和Hashtable都認(rèn)為c1和c2是不同的對(duì)象,都接受了, 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被調(diào)用");
/*下句話(huà),假如不是CompanyMark_to_win類(lèi)型,馬克-to-win:就返回假*/
if (!(o instanceof CompanyMark_to_win)) return false;
CompanyMark_to_win c = (CompanyMark_to_win) o;//downcast,向下轉(zhuǎn)型
return name.equals(c.name);//這個(gè)equals是String的方法
}
public int hashCode() {
System.out.println("hashCode 被調(diào)用 ");
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));//這個(gè)equals會(huì)調(diào)用子類(lèi)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));
}
}
輸出結(jié)果:
equals被調(diào)用
c1.equals(c2): true
hashCode 被調(diào)用
hashCode 被調(diào)用
equals被調(diào)用
set size:1
hashCode 被調(diào)用
hashCode 被調(diào)用
equals被調(diào)用
一樣嗎?true
結(jié)果分析:本例hashcode一樣,所以equals方法被調(diào)用,equals返回值一樣,所以HashSet和Hashtable都認(rèn)為c1和c2是相同的對(duì)象,只接受了1個(gè), size等于1。