java多态别别问题

Art*_*Art 6 java polymorphism pointer-aliasing

如果有3个班级.A,B和C. B类扩展A,C类扩展B.

A类有等于方法:

public boolean equals(A other)
{...}
Run Code Online (Sandbox Code Playgroud)

B级有等于方法:

public boolean equals(B other)
{...}
Run Code Online (Sandbox Code Playgroud)

和C类有euals方法:

public boolean equals(Object other)
{...}
Run Code Online (Sandbox Code Playgroud)

主要有这些代码行:

A a = new A();
C c = new C();
a=c;
System.out.println(a.equals(c));
Run Code Online (Sandbox Code Playgroud)

我无法理解为什么正在执行A类的equals方法.

我知道重载方法是使用静态绑定绑定的.但是指向别名之后的"对象的C部分"并且方法等于C类.为什么不执行C类的equals方法呢?

ajb*_*ajb 7

仅当参数具有相同类型时,子类中的方法才会覆盖超类中的方法.

Object类定义的equals()方法:

class Object {
    public boolean equals(Object obj) {...}
}
Run Code Online (Sandbox Code Playgroud)

定义类时A,它继承了equals例程Object.您定义了一个新的equals,但参数类型不同,因此它不会覆盖其中的一个Object; 相反,它变成了一个过载.结果是A有两个重载equals方法:

class A {
    public boolean equals(Object obj) {...}  // inherited
    public boolean equals(A other) {...}     // the one you wrote
}
Run Code Online (Sandbox Code Playgroud)

同样,equalsin B也不会覆盖equals,所以结果是三个重载equals方法:

class B {
    public boolean equals(Object obj) {...}  // inherited from Object
    public boolean equals(A other) {...}     // inherited from A
    public boolean equals(B other) {...}     // doesn't override anything
}
Run Code Online (Sandbox Code Playgroud)

在类中C,新equals方法覆盖其中的方法Object,因此仍有三种equals方法:

class C {
    public boolean equals(Object other) {...}  // overrides the one in Object
    public boolean equals(A other) {...}       // inherited from A
    public boolean equals(B other) {...}       // inherited from B
}
Run Code Online (Sandbox Code Playgroud)

现在,这是你的代码:

A a = new A();
C c = new C();
a=c;
System.out.println(a.equals(c));
Run Code Online (Sandbox Code Playgroud)

当你说a.equals(c),编译器看到它a有类型A.因此,它会查看方法A以查看要执行的方法.(编译器不知道在运行时a会有类型C;因此,它不会查看中的方法C.)

有两种方法可供选择,如上所示:

    public boolean equals(Object obj) {...}  // inherited
    public boolean equals(A other) {...}     // the one you wrote
Run Code Online (Sandbox Code Playgroud)

他们都可以对参数一起使用c,因为cObject它是一个A.在这种情况下,当一个参数是另一个参数的子类时,编译器实质上选择"最接近"的参数. C只有两个子类A,它是三个子类Object,所以它选择带参数的重载A,这是你定义的A.请注意,此equals方法从未被覆盖.所以它执行你在课堂上编写的代码A.

但是假设你写了:

System.out.println(a.equals((Object)c));
Run Code Online (Sandbox Code Playgroud)

通过强制转换cObject,你迫使编译器将其视为一个Object.现在当它在重载之间选择时,它必须选择带Object参数的那个,因为一个Object 不能自动转换为A(因为不是每个Object都是一个A).因此,它会选择继承的方法.而且,由于在运行时,对象其实是类的C,由于类C有一个equals在覆盖一个方法Object,在这种情况下,它执行写在类的代码C.

您的代码是演示重载和覆盖工作方式的一个很好的示例.然而,在现实生活中,编写一个equals()参数不是其他方法的方法是一个坏主意Object,因为它不会覆盖并且可能导致混淆.此外,最好使用@Override您认为会覆盖超类中方法的任何方法.这样,如果你使用错误的参数,编译器会在你遇到一个很难追查的运行时错误之前捕获它.