判断两个对象是否相等,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 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.


你可能感兴趣的:(java基础)