equals() 的所属以及内部原理(即 Object 中 equals 方法的实现原理)
public boolean equals(Object obj) {
return (this == obj);
}
实际上我们知道所有的对象都拥有标识(内存地址)和状态(数据),同时“==”比较两个对象的的内存地址,所以说 Object 的 equals() 方法是比较两个对象的内存地址是否相等,即若 object1.equals(object2) 为 true,则表示 equals1 和 equals2 实际上是引用同一个对象。
equals() 与 ‘==’ 的区别
总结:默认情况下也就是从超类 Object 继承而来的 equals 方法与 ‘==’ 是完全等价的,比较的都是对象的内存地址,但我们可以重写 equals 方法,使其按照我们的需求的方式进行比较,如 String 类重写了 equals 方法,使其比较的是字符的序列,而不再是内存地址。
equals()的重写规则
-
自反性。对于任何
非null的引用值x,x.equals(x)应返回true。 -
对称性。对于任何
非null的引用值x与y,当且仅当:y.equals(x)返回true时,x.equals(y)才返回true。 -
传递性。对于任何
非null的引用值x、y与z,如果y.equals(x)返回true,y.equals(z)返回true,那么x.equals(z)也应返回true。 -
一致性。对于任何
非null的引用值x与y,假设对象上equals比较中的信息没有被修改,则多次调用x.equals(y)始终返回true或者始终返回false。 -
对于任何非空引用值
x,x.equal(null)应返回false。
当然在通常情况下,如果只是进行同一个类两个对象的相等比较,一般都可以满足以上5点要求。
有父类的时候需要注意覆写父类的 equals 方法:
@Override
public boolean equals(Object obj) {
if (obj instanceof BigCar) {
BigCar bc = (BigCar) obj;
return super.equals(bc) && count == bc.count;
}
return super.equals(obj);
}
为什么重写 equal() 时也得重写 hashCode()
这个问题主要是针对映射相关的操作(Map接口) Map接口的类会使用到键对象的哈希码,当我们调用put方法或者get方法对Map容器进行操作时,都是根据键对象的哈希码来计算存储位置的,因此如果我们对哈希码的获取没有相关保证,就可能会得不到预期的结果。
Objects.hashCode(o) 和 Objects.hash(...o)
Java 7 中对hashCode方法做了两个改进,首先java发布者希望我们使用更加安全的调用方式来返回散列码,也就是使用null安全的方法 Objects.hashCode(注意不是Object而是java.util.Objects) 方法,这个方法的优点是如果参数为null,就只返回0,否则返回对象参数调用的hashCode的结果。
Objects.hashCode 源码如下:
public static int hashCode(Object o) {
return o != null ? o.hashCode() : 0;
}
Java 7 还提供了另外一个方法 java.util.Objects.hash(Object... objects), 当我们需要组合多个散列值时可以调用该方法。
@Override
public int hashCode() {
return Objects.hash(name,salary,sex);
}
在 Java API 文档中关于 hashCode 方法有以下几点规定(原文来自java深入解析一书)。
-
在java应用程序执行期间,如果在
equals方法比较中所用的信息没有被修改,那么在同一个对象上多次调用hashCode方法时必须一致地返回相同的整数。如果多次执行同一个应用时,不要求该整数必须相同。 -
如果两个对象通过调用
equals方法是相等的,那么这两个对象调用hashCode方法必须返回相同的整数。 -
如果两个对象通过调用
equals方法是不相等的,不要求这两个对象调用hashCode方法必须返回不同的整数。 但是程序员应该意识到对不同的对象产生不同的hash值可以提供哈希表的性能。
编写一个完美equals()的几点建议
(出自Java核心技术 第一卷:基础知识)
-
(1)显式参数命名为
otherObject, 稍后需要将它转换成另一个叫做other的变量 -
(2)检测
this与otherObject是否引用同一个对象 :if(this == otherObject) return true;(存储地址相同,肯定是同个对象,直接返回true) -
(3) 检测
otherObject是否为null,如果为null,返回false:if(otherObject == null) return false; -
(4) 比较
this与otherObject是否属于同一个类 (视需求而选择)-
如果equals的语义在每个子类中有所改变,就使用
getClass检测 :if(getClass()!=otherObject.getClass()) return false -
如果所有的子类都拥有统一的语义,就使用
instanceof检测 :if(!(otherObject instanceof ClassName)) return false
-
-
(5) 将
otherObject转换为相应的类类型变量:ClassName other = (ClassName) otherObject; -
(6) 现在开始对所有需要比较的域进行比较 。使用 == 比较基本类型域,使用 equals 比较对象域。如果所有的域都匹配,就返回
true,否则就返回false。
如果在子类中重新定义 equals,就要在其中包含调用super.equals(other)
当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定: 相等对象必须具有相等的哈希码 。
关于 list.contains(o) 方法: 其实内部是for循环拿 o.equals(a[i]) 去比较的
@Override
public boolean contains(Object o) {
return indexOf(o) != -1;
}
@Override
public int indexOf(Object o) {
E[] a = this.a;
// 当o是null的时候也会返回集合中null的位置
if (o == null) {
for (int i = 0; i < a.length; i++)
if (a[i] == null)
return i;
} else {
// indexOf(),实际调用的是传入的contains(Object o)的实参的equals方法
for (int i = 0; i < a.length; i++)
if (o.equals(a[i]))
return i;
}
return -1;
}
参考:https://blog.csdn.net/javazejian/article/details/51348320
本文详细介绍了Java中equals()方法的工作原理及其与'=='操作符的区别。探讨了equals()方法的重写规则,并给出了最佳实践建议。

3106

被折叠的 条评论
为什么被折叠?



