判斷兩個物件是否相等,hashcode和equals方法的聯絡
1、在集合中考慮兩個物件是否相同的規則是:
第一步:如果hashCode()相等,則進行第二步,否則不相同。
第二步:檢視equals()相等就相等,否則不相同
2、hashcode是物件或者變數通過雜湊演算法計算出來的hash值,不同物件是不一樣的,同一個物件是不變的。
3、equals()相等,hashcode一定相等
hashcode不相等,equals一定不相同
4、在重寫類的equals()方法時都會重寫hashcode()方法。
如果重寫了equals(),但是沒有重寫hashcode()則會造成如下問題。
public class ObjectClass {
public static void main(String[] args) {
Set<Demo1> demo1Set=new HashSet<>();
Demo1 demo1=new Demo1(1,2);
Demo1 demo2=new Demo1(3,4);
Demo1 demo3=new Demo1(5,6);
demo1Set.add(demo1);
demo1Set.add(demo2);
demo1Set.add(demo3);
System.out.println(demo1Set);
Demo1 demo4=new Demo1(1,2);
demo1Set.add(demo4);
System.out.println(demo1Set);
System.out.println(demo1.hashCode());
System.out.println(demo4.hashCode());
System.out.println(demo1.hashCode());
}
}
class Demo1{
private int value;
private int id;
public Demo1(int value,int id){
this.value=value;
this.id=id;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Demo1 demo1 = (Demo1) o;
if (id != demo1.id) return false;
if (value != demo1.value) return false;
return true;
}
// @Override
// public int hashCode() {
// int result = value;
// result = 31 * result + id;
// return result;
// }
@Override
public String toString() {
return "Demo1{" +
"value=" + value +
", id=" + id +
'}';
}
}
會造成set中有重複的資料
[Demo1{value=3, id=4}, Demo1{value=1, id=2}, Demo1{value=5, id=6}]
[Demo1{value=3, id=4}, Demo1{value=1, id=2}, Demo1{value=1, id=2},Demo1{value=5, id=6}]
2133927002
1173230247
2133927002
也就是說,在這種情況下,不重新寫hashcode方法,兩個物件是的hashcode值Object方法裡面是不一樣的。所以set集合裡面就會認為是兩個不同的物件,所以會都有。所以重寫了equals方法必須重寫hashcode方法。
例項應用:
public static boolean isAllSelected(WipPackage wipPackage, WiseNewsSession wiseNewsSession) { ConfigManager configManager = wiseNewsSession.getConfigManager(); WipPackage wipPackageFrom4VS=getWipPackage4VS(wiseNewsSession, configManager); return wipPackageFrom4VS.equals(wipPackage); }
比較wipPackageFrom4VS和wipPackage兩個物件是否相等。顯然如果不重寫WipPackage的hashCode()方法
這兩個物件的hashCode值是不相等的(因為是不同的物件)。那麼既然兩個物件的hashcode值不相等,
即使兩個物件對應欄位的值相等,equals()方法也一定是false。
so
@Override public boolean equals(Object o) { if (this == o) { return true; } if (o == null || getClass() != o.getClass()) { return false; } WipPackage that = (WipPackage) o; if (wisesearch != that.wisesearch) { return false; } if (wisesearchpro != that.wisesearchpro) { return false; } if (video != that.video) { return false; } if (cartoon != that.cartoon) { return false; } if (web != that.web) { return false; } if (ad != that.ad) { return false; } return wiselive == that.wiselive; } @Override public int hashCode() { int result = (wisesearch ? 1 : 0); result = 31 * result + (wisesearchpro ? 1 : 0); result = 31 * result + (video ? 1 : 0); result = 31 * result + (cartoon ? 1 : 0); result = 31 * result + (web ? 1 : 0); result = 31 * result + (ad ? 1 : 0); result = 31 * result + (wiselive ? 1 : 0); return result; }
那麼另一個問題來了,怎麼重寫hashCode()方法和equals()方法呢?
一定要確保兩個物件的欄位相同,hashCode()和equals()就相同。
那麼為什麼要乘以31呢?
The
value 31 was chosen because it is an odd prime. If it were even and the multiplication overflowed, information would be lost, as multiplication by 2 is equivalent to shifting. The advantage of using a prime is less clear, but it is traditional. A nice property
of 31 is that the multiplication can be replaced by a shift and a subtraction for better performance: 31
* i == (i << 5) - i
. Modern VMs do this sort of optimization automatically.