Я хочу знать, почему второй оператор печати создает "одну реализацию", как и вывод, ниже приведен код Java
class Point {
public boolean equals(final Object anObject) {
System.out.println("One implementation.");
return false;
}
public boolean equals(final Point aPoint) {
System.out.println("Another implementation.");
return false;
}
}
public class Main {
public static void main(final String[] args) {
final Point p1 = new Point();
final Point p2 = new Point();
final Object o = p1;
System.out.println(p1.equals(p2));
System.out.println(o.equals(p2));
System.out.println(p1.equals(o));
}
}
Выход:-
Другая реализация
ложный
Одна реализация {проблема}
ложный
Одна реализация
ложный




Метод
boolean equals(Object other);
перегружает базовый метод объекта; Этот метод
boolean equals(Point other);
не. Итак, когда вы вызываете Object.equals(), что вы делаете во втором случае, вы попадаете в первую предоставленную вами реализацию. Переопределение Object.equals() — это то, что вам нужно сделать как минимум; другие реализации необязательны и, на мой взгляд, могут ввести в заблуждение.
Следует аннотировать переопределения с помощью @Override; это может помочь избежать путаницы в отношении того, действительно ли таковым является предполагаемое переопределение.
Вы можете использовать утилиту javap с флагами -c -v, чтобы лучше понять, что происходит, полная команда javap -c -v Main, ее вывод (я обрезал его)
public static void main(java.lang.String[]);
Code:
0: new #2 // class Main$Point
3: dup
4: invokespecial #3 // Method Main$Point."<init>":()V
7: astore_1
8: new #2 // class Main$Point
11: dup
12: invokespecial #3 // Method Main$Point."<init>":()V
15: astore_2
16: aload_1
17: astore_3
18: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
21: aload_1
22: aload_2
23: invokevirtual #5 // Method Main$Point.equals:(LMain$Point;)Z
26: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
29: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
32: aload_3
33: aload_2
34: invokevirtual #7 // Method java/lang/Object.equals:(Ljava/lang/Object;)Z
37: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
40: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
43: aload_1
44: aload_3
45: invokevirtual #8 // Method Main$Point.equals:(Ljava/lang/Object;)Z
48: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
51: return
Другими словами, компилятор Java преобразовал второй вызов в java/lang/Object.equals, потому что тип переменной o — Object. Java является статически типизированным языком, поэтому все разрешения типов происходят во время компиляции, поэтому не имеет значения, будет ли переменная o назначена Point во время выполнения.