突击系列之【JAVA基础】hashCode,equals,==

本文详细解析了Java中equals和hashCode方法的运作机制,强调了它们在对象比较和哈希表性能中的作用,以及重写时的一致性要求。

目录:

  1. Object类下的equals和hashCode:

  2. == 和 equals

  3. hashCode码的特点

  4. 为什么重写equals建议一定要重写hashCode?

Object类下的equals和hashCode:

public boolean equals(Object obj) {
    return (this == obj);
}
public native int hashCode();

== 和 equals

对于值对象,比较的是两个对象的值
对于引用对象,
比较的是两个对象的地址

如上代码Object类下的equals 通过==对比是当前对象和传入对象是否是同一个对象,对比的是两个对象的地址
也就是即使是对象里面的值都是一样的,也会被判,这两对象不相等。通过代码来理解一下这句话:

public class Cat {
    int color,weight,height;

    public Cat(int color,int weight,int height){
        this.color = color;
        this.weight = weight;
        this.height = height;
    }
}
 public static void main(String[] args) {
        Cat c1 = new Cat(1, 1, 1);
        Cat c2 = new Cat(1, 1, 1);
		
        System.out.println("c1==c2的结果是:"+(c1==c2));
        System.out.println("c1.equals(c2)的结果是:"+c1.equals(c2));

        System.out.println("c1.hashCode="+c1.hashCode());
        System.out.println("c2.hashCode="+c2.hashCode());
}

c1==c2的结果是:false
c1.equals(c2)的结果是:false
c1.hashCode=356573597
c2.hashCode=1735600054

通过结果可以知道:即使是一样的属性的Cat对象,hashcode和equals都是不同的。
引用equals调用的是object的equals方法,通过thisobject判断当前对象和传入的对象也就是c1和c2的引用是否是同一个,答案当然是不一样,所以equals的结果和的结果是一样的,都是false。

不同对象他们的hashCode是不一样的。
但思考:不同对象的hashCode一定是不一样的?

hashCode码的特点

上面提到,不同对象的hashCode一定是不一样的?—不是
那么反过来呢?
一样的hashCode,一定是同一个对象吗?----不是
相同对象的hashCode一定是一样的吗?-----是
TODO:深入原理不太明白,看源码注释可以看到:

 /**
     * Returns a hash code value for the object. This method is
     * supported for the benefit of hash tables such as those provided by
     * {@link java.util.HashMap}.
     * <p>
     * The general contract of {@code hashCode} is:
     * <ul>
     * <li>Whenever it is invoked on the same object more than once during
     *     an execution of a Java application, the {@code hashCode} method
     *     must consistently return the same integer, provided no information
     *     used in {@code equals} comparisons on the object is modified.
     *     This integer need not remain consistent from one execution of an
     *     application to another execution of the same application.
     * <li>If two objects are equal according to the {@code equals(Object)}
     *     method, then calling the {@code hashCode} method on each of
     *     the two objects must produce the same integer result.
     * <li>It is <em>not</em> required that if two objects are unequal
     *     according to the {@link java.lang.Object#equals(java.lang.Object)}
     *     method, then calling the {@code hashCode} method on each of the
     *     two objects must produce distinct integer results.  However, the
     *     programmer should be aware that producing distinct integer results
     *     for unequal objects may improve the performance of hash tables.
     * </ul>
     * <p>
     * As much as is reasonably practical, the hashCode method defined by
     * class {@code 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
     * Java&trade; programming language.)
     *
     * @return  a hash code value for this object.
     * @see     java.lang.Object#equals(java.lang.Object)
     * @see     java.lang.System#identityHashCode
     */
    public native int hashCode();
  • If two objects are equal according to the {@code equals(Object)}
 *     method, then calling the {@code hashCode} method on each of
 *     the two objects must produce the same integer result.
 *   如果根据{@code equals(Object)}两个对象相等方法,然后对每个

这两个对象必须产生相同的整数结果

为什么重写equals建议一定要重写hashCode?

hashCode的计算基础是根据equals来计算的。如上,相同对象的hashcode一定是一样的。
在使用hashCode和equals的时候,是通过先对比hashCode,看hashCode如果相同,再对比equals,如果equals的结果是true,则表示两个对象一样的。如果hashCode不同,那么就认定这两个对象不同了。

所以,如果你更换的equals的对比规则,但是没有更新hashCode的计算规则,即使equals是true,但是hashCode还是按照this==object的规则进行对比的,那么存储的时候hashCode的值也是按照不同对象去存储的,所以会出现本来是相同对象,却按照两个不同对象取出的情况。

举个例子:
HashSet,set集合的特定就是存储的对象是惟一的

 public static void main(String[] args) {
        HashSet<RectObject> set = new HashSet<RectObject>();
        RectObject r1 = new RectObject(3,3);
        RectObject r2 = new RectObject(5,5);
        RectObject r3 = new RectObject(3,3);
        System.out.println("r1.equals(r3)的结果:"+r1.equals(r3));
        System.out.println("r1.hashCode()"+r1.hashCode());
        System.out.println("r3.hashCode()"+r3.hashCode());
        
        set.add(r1);
        set.add(r2);
        set.add(r3);
        System.out.println("Set集合的size:"+set.size());
    }

r1.equals(r3)的结果:true
r1.hashCode()356573597
r3.hashCode()1735600054
Set集合的size:3

从结果可以看到,虽然r1和r3的结果是true, 但是Set集合却当做两个不同的对象插入了。

原因在于:
RectObject类中重写了equals方法,没有重写hashCode方法

public class RectObject {
    public int x;
    public int y;

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (o == null || getClass() != o.getClass()) return false;
        RectObject that = (RectObject) o;
        return x == that.x &&
                y == that.y;
    }

//    @Override
//    public int hashCode() {
//        return Objects.hash(x, y);
//    }
}

重写了hashCode之后的运行结果:
r1.equals(r3)的结果:true
r1.hashCode()1057
r3.hashCode()1057
Set集合的size:2

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

邢美玲

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值