java多态别别问题

时间:2017-03-25 04:01:30

标签: java polymorphism aliasing

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

A类有等于方法:

public boolean equals(A other)
{...}

B类有等于方法:

public boolean equals(B other)
{...}

和C类有euals方法:

public boolean equals(Object other)
{...}

主要有这些代码行:

A a = new A();
C c = new C();
a=c;
System.out.println(a.equals(c));

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

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

3 个答案:

答案 0 :(得分:7)

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

Object类定义了equals()方法:

class Object {
    public boolean equals(Object obj) {...}
}

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

class A {
    public boolean equals(Object obj) {...}  // inherited
    public boolean equals(A other) {...}     // the one you wrote
}

同样,equals中的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
}

在课程C中,新的equals方法 会覆盖Object中的方法,因此仍有三种equals方法:< / p>

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
}

现在,这是你的代码:

A a = new A();
C c = new C();
a=c;
System.out.println(a.equals(c));

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

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

    public boolean equals(Object obj) {...}  // inherited
    public boolean equals(A other) {...}     // the one you wrote

它们都可用于参数c,因为cObject,而且是A。在这种情况下,当一个参数是另一个参数的子类时,编译器实质上选择“最接近”的参数。 C只是远离A的两个子类,它距离Object只有三个子类,因此它选择带参数A的重载,这是您在{中定义的那个{1}}。请注意,此A方法从未被覆盖。因此它执行您在类equals中编写的代码。

但是假设你写了:

A

通过将System.out.println(a.equals((Object)c)); 强制转换为c,您迫使编译器将其视为Object。现在,当它在重载之间进行选择时,它必须选择具有Object参数的那个,因为Object 不能自动转换为Object(因为不是每个A都是Object)。因此,它会选择继承的方法。而且,因为在运行时,该对象实际上属于类A,并且因为类C具有覆盖C中的equals方法,所以在这种情况下它执行类Object中编写的代码。

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

答案 1 :(得分:4)

简短回答

只有当子类具有与父类相同的方法签名时,才会在子类中获取重写。否则它就没有了。

考虑这两个例子

示例1

class A {
    public boolean equals(A Other) {
        System.out.println("A's method");
        return true;
    }
}

class C extends A {
    public boolean equals(Object Other) {
        System.out.println("C's method");
        return true;
    }
}

public class Driver {
    public static void main(String[] args) {
        A a = new C();
        a.equals(null);
    }
}

输出1

A's method

示例2

class A {
    public boolean equals(A Other) {
        System.out.println("A's method");
        return true;
    }
}

class C extends A {
    public boolean equals(A Other) {
        System.out.println("C's method");
        return true;
    }
}

public class Driver {
    public static void main(String[] args) {
        A a = new C();
        a.equals(null);
    }
}

输出2

C's method

在示例#1中,您在子类中定义equals()方法时更改了方法签名,因此它不符合方法覆盖的条件。因此,当从Driver类调用此方法时,将调用父级。

在示例#2中

,父和子中的方法签名完全相同,因此方法覆盖在此发生,因此您得到的输出是期待你的问题。

答案 2 :(得分:1)

简单来说,java在运行时处理别名。因为重载方法使用静态绑定(编译时),所以它调用A的equals方法。 如果你在A类中重写equals方法。

@Override
public boolean equals(Object o){ ...}

将覆盖使用动态绑定(运行时)的方法,并调用C的equals方法。