小概

==,hashCode() 与 equals() ,这三个操作在 Java 程序当中满地都是,特别是容器里,如 Map 中的哈希映射与搜索元素就是根据
hashCode() 和 equals() 判断的,所以如何正确的理解和使用显得非常重要,并且在封装类的时候,十分建议通通重写

我们先要知道这个概念,每个线程都有属于自己的 虚拟机栈,虚拟机栈中的元素我们称之为 栈帧,每运行一个方法时,虚拟机会为这个方法创建一个栈帧,并入栈,方法结束后便出栈

那么我们操作的变量有两种

  • 局部变量:存在当前栈帧的局部变量表里,如果是基本数据类型便是值的大小,如果是对象便是一个指向堆内存中对象地址的引用

  • 全部变量:存在方法区中,存储规则一样

所以我们比较的,是 基本数据类型的大小引用地址

a == b

比较规则

  1. 当a,b 为对象时,表示两者 引用地址 是否相同,即堆内存中地址是否相同

  2. 当a,b 为基本数据类型时,表示两者 数据大小 是否相等

a.equals(b)

假设 a 的对象类型为 A

比较规则

  1. a,b 只能为对象,表示两者 对象属性 是否相等,如 String 就是比较内部维护的 char[] 数组每一个字符是否相等

  2. 为了简化比较复杂度,往往会先判断 a == b,如果它们都指向同一个地址,那么两者内容肯定一样,则不需要逐一比较对象内容中的值

我们可以认为,== 和 equals 的推导关系是 充分不必要

  • == 成立则 equals 成立

  • equals 成立,== 不一定成立

如何比较属性

比如区分两个学生是否是同一个学生,我们其实只需要查看他们的学号是否相同就行了

也就是我们应该比较能唯一标识这个对象的一个甚至多个对象属性,情况完全视不同对象而定

如果 A 未重写 equals()

如果 A 未重写时,调用的是父类的 equals(),还未重写,会检查到 Object,而 Object 是如下比较的

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

利用 == 号比较对象内容是否相等未必有点草率,因此我们对这个方法应当十分谨慎

如何重写

重写时需注意应当满足如下规则,摘自 《Effective Java》

  1. 自反性:x.equals(x)必须返回true

  2. 对称性:x.equals(y)与y.equals(x)的返回值必须相等

  3. 传递性:x.equals(y)为true,y.equals(z)也为true,那么x.equals(z)必须为true

  4. 一致性:如果对象x和y在equals()中使用的信息都没有改变,那么x.equals(y)值始终不变

  5. 非null:x不是null,y为null,则x.equals(y)必须为false

在这里建议按以下规则重写

  1. 建议判断 a == b,省去没必要的比较

  2. 建议先判断 b instanceOf A,再做能能标识唯一对象的一个或多个属性的比较

  3. 建议考虑 super.equals(b)

a.hashCode()

该方法返回的是对象的哈希值,主要应用于哈希容器映射时,将所有类型对象映射成整数

如何重写

在这里建议按以下规则重写

  1. 建议对能标识唯一对象的一个或多个属性进行 hashCode() 重写

  2. 建议利用 jdk 基础封装类的 hashCode()

  3. 建议考虑 super.equals(b)


linckye
32 声望1 粉丝

成功捕获一枚 Java