正确覆盖equals方法

4

我的老师给了我一个关于a等于覆盖示例的解决方案,如下所示:

@Override
public boolean equals(Object o)
{
    if (this == o) return true;
    boolean result = false;
    if (o instanceof Product)
    {
        Product other = (Product)o;
        result = this.id == other.id;
    }
    return result;
}

该方法被覆盖为Product类,其中具有每个产品唯一的属性id。但我不理解第一个if的意思,我认为第二个if已经检查了第一个if的限制。有人可以给我一个此代码工作的示例,以及下面这个代码不行的示例吗?谢谢!

@Override
public boolean equals(Object o)
{
    boolean result = false;
    if (o instanceof Product)
    {
        Product other = (Product)o;
        result = this.id == other.id;
    }
    return result;
}
4个回答

4
两个代码示例都可以工作。第一个示例中的 if (this == o) return true; 是一种性能优化(很可能是过早优化 - 总是先进行分析),它检查对象是否与自身进行比较。在Java中,==运算符比较的是两个对象是否是同一实例,而不是是否是具有相同数据的不同实例。
equals方法有许多编写风格。以下是我通常的做法:
public boolean equals(Object obj) {
    if (obj instanceof Product) {
        Product that = (Product) obj;
        return this.id == that.id;
    }
    return false;
}

如果我知道我的代码永远不会将对象与其他类型的对象或null进行比较,那么我甚至可以编写如下所示的代码,以便在任何情况下都会抛出异常 - 这意味着我的代码存在错误,因此通过尽早失败,我将更快地发现并修复它。

public boolean equals(Object obj) {
    Product that = (Product) obj;
    return this.id == that.id;
}

保留==测试的原因是为了避免instanceof迭代器和强制转换的类检查的双重开销。(但是,当它跟随一个instanceof测试时,一些编译器会优化第二个开销。) - Ted Hopp
Java编译器现在会进行优化吗,还是这个任务留给了Hotspot虚拟机? - Fortyrunner
我检查过的所有Java编译器的输出都没有进行任何优化,除了消除死代码等微不足道的优化。 - aioobe
不是Java编译器(javac)进行优化,而是JIT编译器(例如HotSpot)在运行时进行优化。您需要使用JVM的调试版本才能查看生成的本机代码:http://stackoverflow.com/questions/3578992/how-to-find-native-instructions-generated-from-class-file - Esko Luontola

0

你说得对。第一个if语句是多余的,因为this == o意味着o instanceof Productthis.id == other.id

如果参数是性能,我会说这似乎是过早优化的味道。


1
从逻辑上讲是多余的,但从性能的角度来看并不多余。instanceof运算符非常缓慢,并且强制转换会导致ClassCastException的检查(尽管一些编译器会优化掉这个检查,如果强制转换紧随一个instanceof测试)。 - Ted Hopp
然而,除非它是瓶颈的一部分,否则这是毫无意义的。 - aioobe
1
instanceof在早期虚拟机中是很慢的。但考虑到我们已经看到了许多HotSpot优化,我怀疑这对于低使用率的情况来说并不会太慢以至于影响程序性能。话虽如此,我仍建议先检查对象相等性! - Fortyrunner

0
在Eclipse中,您可以选择“生成hashCode()和equals()…”(菜单源代码)。

0
if (this == o) return true;

上述语句是多余的。

更具体地说,它只是检查您是否将一个对象与自身进行比较...因此可以跳过其下面的代码。例如:

Foo f = new Foo();
f.equals(f); //the if (this == o) would be true. References the same thing.

注意:顺便提一下,如果重写equals方法,应该同时重写hashcode()方法以维护hashcode()的一般契约 - 相等的对象必须具有相同的hashcode(反之不成立,因为两个对象可能具有相同的hashcode但不相等)。

http://download.oracle.com/javase/6/docs/api/java/lang/Object.html#equals(java.lang.Object)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接