英文:
Java equals confusion
问题
假设我在圆形类(Circle class)中有两个 equals 方法,
public boolean equals(Object obj);
public boolean equals(Circle circle);
然后我进行了以下操作:
Circle c1 = new Circle(new Point(0, 0), 10);
Circle c2 = new Circle(new Point(0, 0), 10);
Object o1 = c1;
Object o2 = c2;
对于 o1.equals(c1);
,为什么会调用 equals(Object obj)
而不是 equals(Circle circle)
?
英文:
Suppose I have 2 equals method in the circle class,
public boolean equals(Object obj);
public boolean equals(Circle circle);
And I do this:
Circle c1 = new Circle(new Point(0, 0), 10);
Circle c2 = new Circle(new Point(0, 0), 10);
Object o1 = c1;
Object o2 = c2;
For o1.equals(c1);
why does it call the equals(Object obj)
instead of equals(Circle circle)
?
答案1
得分: 3
声明类型决定了你可以调用哪些方法,实际类型决定了要使用哪个实现。如果你调用 o1.equals(c1)
,因为声明类型是 Object
,编译器会在 Object
中找到要使用的方法,即 equals(Object obj)
。如果你调用 c2.equals(c1)
,这时声明类型是 Circle
,编译器会根据 Java 的方法重载解析机制发现 equals(Circle)
比 equals(Object)
更合适。
实际上,你可以将这两个 equals
方法视为两个完全不同的方法,只是碰巧具有相同的名称。
英文:
The declared type decide what kinds of methods you can call, the real type decide what implementationi to use.
If you call o1.equals(c1)
, because the decalred type is Object
,the compiler will find method in Object
to use which is equals(Object obj)
.
if you call c2.equals(c1)
, this time the declared type is Circle
, the compiler will find that equals(Circle)
is better than equals(Object)
with java's method overload resolution mechanism.
In fact you can view the two equals method as two totally different method which happens to have same name.
答案2
得分: 0
这个确切的情况在《Effective Java》中有描述。来自第三版第49页,
不要在equals声明中为Object替代另一种类型。 程序员常常会编写一个看起来像这样的equals方法,然后花费数小时来解决为什么它不起作用的难题:
// 错误 - 参数类型必须是Object!
public boolean equals(MyClass o) {
...
}
问题在于,这个方法没有覆盖 Object.equals
,后者的参数是Object
类型,而是重载了它。 即使是在正常的equals方法之外提供这样一个“强类型”的equals方法也是不可接受的,因为它可能会导致子类中的Override
注解生成错误的结果,并提供虚假的安全感。
英文:
This exact scenario is described in Effective Java. From page 49 of the third edition,
> Don’t substitute another type for Object in the equals declaration. It is not uncommon for a programmer to write an equals method that looks like this and then spend hours puzzling over why it doesn’t work properly:
// Broken - parameter type must be Object!
public boolean equals(MyClass o) {
...
}
> The problem is that this method does not override Object.equals
, whose argument is of type Object
, but overloads it instead. It is unacceptable to provide such a “strongly typed” equals
method even in addition to the normal one, because it can cause Override
annotations in subclasses to generate false positives and provide a false sense of security.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论