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 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.