Javaequals()方法
示例
TL;DR
==测试引用是否相等(它们是否是同一对象)
.equals()测试值是否相等(在逻辑上是否为“相等”)
equals()是用于比较两个对象是否相等的方法。当且仅当两个引用都指向同一实例时equals(),Object该类中方法的默认实现true才返回。因此,它的行为与通过进行比较的行为相同==。
public class Foo {
int field1, field2;
String field3;
public Foo(int i, int j, String k) {
field1 = i;
field2 = j;
field3 = k;
}
public static void main(String[] args) {
Foo foo1 = new Foo(0, 0, "bar");
Foo foo2 = new Foo(0, 0, "bar");
System.out.println(foo1.equals(foo2)); //打印错误
}
}即使foo1和foo2使用相同的字段创建,它们仍指向内存中的两个不同对象。equals()因此,默认实现的计算结果为false。
要比较一个对象的内容是否相等,equals()必须重写。
public class Foo {
int field1, field2;
String field3;
public Foo(int i, int j, String k) {
field1 = i;
field2 = j;
field3 = k;
}
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Foo f = (Foo) obj;
return field1 == f.field1 &&
field2 == f.field2 &&
(field3 == null ? f.field3 == null : field3.equals(f.field3));
}
@Override
public int hashCode() {
int hash = 1;
hash = 31 * hash + this.field1;
hash = 31 * hash + this.field2;
hash = 31 * hash + (field3 == null ? 0 : field3.hashCode());
return hash;
}
public static void main(String[] args) {
Foo foo1 = new Foo(0, 0, "bar");
Foo foo2 = new Foo(0, 0, "bar");
System.out.println(foo1.equals(foo2)); //打印真实
}
}equals()如果对象的字段相同,则覆盖方法在此处确定对象相等。
注意,该hashCode()方法也被覆盖。该方法的约定规定,当两个对象相等时,它们的哈希值也必须相同。这就是为什么人们几乎总是必须超越hashCode()并equals()在一起。
特别注意方法的参数类型equals。是的Objectobj,不是Fooobj。如果将后者放入您的方法中,则这不是该equals方法的替代。
在编写自己的类时,您必须在覆盖equals()和时编写类似的逻辑hashCode()。大多数IDE可以自动为您生成此代码。
equals()可以在String类中找到实现的示例,该类是核心JavaAPI的一部分。String该类不是比较指针,而是比较的内容String。
Java1.7引入了java.util.Objects提供便利方法的类,该类equals比较了两个潜在的null引用,因此可以用来简化该equals方法的实现。
@Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null || getClass() != obj.getClass()) {
return false;
}
Foo f = (Foo) obj;
return field1 == f.field1 && field2 == f.field2 && Objects.equals(field3, f.field3);
}类比较
由于equals方法可以针对任何对象运行,因此该方法经常要做的第一件事(检查null)是检查被比较对象的类是否与当前类匹配。
@Override
public boolean equals(Object obj) {
//...检查是否为空
if (getClass() != obj.getClass()) {
return false;
}
//...比较字段
}通常,通过比较类对象,如上所述完成此操作。但是,这在一些不太明显的特殊情况下可能会失败。例如,某些框架生成类的动态代理,而这些动态代理实际上是不同的类。这是使用JPA的示例。
Foo detachedInstance = ...
Foo mergedInstance = entityManager.merge(detachedInstance);
if (mergedInstance.equals(detachedInstance)) {
//如果使用getClass()测试相等性,将永远无法到达这里
//因为mergedInstance是Foo的代理(子类)
}解决该限制的一种机制是使用instanceof
@Override
public final boolean equals(Object obj) {
if (!(obj instanceof Foo)) {
return false;
}
//...比较字段
}但是,使用时必须避免一些陷阱instanceof。由于Foo可能具有其他子类,并且这些子类可能会覆盖,因此equals()您可能会遇到aFoo等于aFooSubclass但aFooSubclass不等于的情况Foo。
Foo foo = new Foo(7); FooSubclass fooSubclass = new FooSubclass(7, false); foo.equals(fooSubclass) //true fooSubclass.equals(foo) //false
这违反了对称性和传递性的属性,因此是该equals()方法的无效实现。结果,当使用时instanceof,一个好的做法是制作该equals()方法final(如上例所示)。这将确保没有子类覆盖equals()并违反关键假设。