Java的equal()和hashCode()

参考文献:https://juejin.im/post/6844904005575901191

 

Java中经常会问这样的问题:为什么定义一个类,如果重写equal()就一定要重写hashCode()?

这个问题可以分成几步来看:

        什么是equal?

        什么是hashCode?

        为什么要重写equal() ?

        为什么要在重写完equal()之后重写hashCode()?

 

1. equal()方法是什么?

Object中,equal 的方法如下

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

很明显,认为相等的前提是认为两个地址相等,这种方式对于基础类型是可以的,比如int,float等

但是对于自定义的一个类型,新建的两个类,用equal地址会不同,所以无法认为是相等。

而通过Java文档中的equals()方法描述,所有要实现自己的equals()方法都要遵守下面几个规则

  • 自反性:对于任何对象x,x.equals(x)应该返回true
  • 对称性:对于任何两个对象x和y,如果x.equals(y)返回true,那么y.equals(x)也应该返回true
  • 传递性:对于多个对象x,y,z,如果x.equals(y)返回true,y.equals(z)返回true,那么y.equals(z)也应该返回true
  • 一致性:对于两个非空对象x,y,在没有修改此对象的前提下,多次调用返回的结果应该相同
  • 对于任何非空的对象x,x.equals(null)都应该返回false

 

2. hashCode()方法是什么?

Object中的hashCode()方法是一个本地方法,返回一个int类型的哈希值,定义不同的Obejct,返回的值都不同。

public native int hashCode();

hashCode()方法中也有一些规约

  • 如果对象在使用equals方法中进行比较的参数没有修改,那么多次调用一个对象的hashCode()方法返回的哈希值应该是相同的。
  • 如果两个对象通过equals方法比较是相等的,那么要求这两个对象的hashCode方法返回的值也应该是相等的。
  • 如果两个对象通过equals方法比较是不同的,那么也不要求这两个对象的hashCode方法返回的值是不相同的。但是我们应该知道对于不同对象产生不同的哈希值对于哈希表(HashMap等等)能够提高性能。

什么是native方法?

        Java是无法访问到操作系统底层的,所以需要使用native(本地方法)来扩展Java程序的功能。

        从使用的角度:这种方法类似于接口,不需要实现,直接就可以给出随机的返回值,如上边的hashCode()就会直接根据C++底层的结果,返回一个确定的值。

        从实现原理的角度:

          1. 在Java中声明native方法,然后编译。

          2. javah产生一个.h文件。

         3. 写一个.cpp文件实现native导出方法,其中需要包含第二步产生的.h文件(注意其中又包含了JDK带的jni.h文件)。

         4 . 将第三步的.cpp文件编译成动态链接库文件。

         5. 在Java中用System.loadLibrary()方法加载第四步产生的动态链接库文件,这个native方法就可以在Java中被访问了。

 

3. 为什么要重写equal? 为什么要重写hashCode?

        重写equal()方法最常见的地方是Map。

        Map在通过Key找Value值的时候,会调用hashCode方法,先找到这个对象是否有相同的hashCode。

                如果没有,则认为这个Map中没有想找的类型。

                如果有hashCode值,就接着调用equals方法,判断是否相等,这样才可以完整的取出value。

        Map在存储的时候同样使用了这种方式,在一个数据存储完成之后,下一个数据会遍历Map中的Key的hashCode值:

                如果hashCode相同,调用equal判断是否一样,一样则覆盖了之前的文件

                如果hashCode不同,则无需判断equal,直接认为是两个不同的值,这种很容易出现一个类型存储了多个key的情况。

        比如如下两段代码,最后输出的肯定是null。

        原因就在于Map,没有重新写equal和hashCode,但是解开注释,就可以解决这个问题了。

package Temp1;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

public class Temp {
    public static void main(String[] args) {
        Map<CustomizedKey, Integer> data = getData();
        CustomizedKey key = new CustomizedKey(10,"abc");
        System.out.println("hashCode2:" + key.hashCode());
        Integer integer = data.get(key);
        System.out.printf(String.valueOf(integer));
    }

    private static Map<CustomizedKey, Integer> getData() {
        Map<CustomizedKey, Integer> customizedKeyIntegerMap = new HashMap<>();
        CustomizedKey key = new CustomizedKey(10,"abc");
        System.out.println("hashCode1:" + key.hashCode());
        customizedKeyIntegerMap.put(key, 10);
        return customizedKeyIntegerMap;
    }
}
package Temp1;

import javafx.scene.NodeBuilder;

import java.util.Objects;

public class CustomizedKey {
    private Integer id;
    private String name;

    public CustomizedKey(int id, String name) {
        this.id = id;
        this.name = name;
    }

//    @Override
//    public boolean equals(Object o) {
//        if (this == o) return true;
//        if (o == null || getClass() != o.getClass()) return false;
//        CustomizedKey that = (CustomizedKey) o;
//        return Objects.equals(id, that.id) &&
//                Objects.equals(name, that.name);
//    }

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


 

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值