Java 重载和继承规则

2022-09-01 07:45:24

我一直在学习,因为我有一个考试,我对大多数Java没有太多问题,但我偶然发现了一个我无法解释的规则。下面是一个代码片段:

public class A {

    public int method(Object o) {
        return 1;
    }

    public int method(A a) {
        return 2;
    }
}

public class AX extends A {

    public int method(A a) {
        return 3;
    }

    public int method(AX ax) {
        return 4;
    }
}

public static void main(String[] args) {
    Object o = new A();
    A a1 = new A();
    A a2 = new AX();
    AX ax = new AX();

    System.out.println(a1.method(o));
    System.out.println(a2.method(a1));
    System.out.println(a2.method(o));
    System.out.println(a2.method(ax));
}

这将返回:

1 3 1 3

虽然我希望它能回来:

1 3 1 4

为什么 a2 的类型决定了在 AX 中调用哪个方法?

我一直在阅读有关重载规则和继承的内容,但这似乎足够晦涩难懂,以至于我无法找到确切的规则。任何帮助将不胜感激。


答案 1

这些方法调用的行为由 Java 语言规范(参考第 8.4.9 节)规定和描述。

调用方法时 (§15.12),在编译时将使用实际参数(以及任何显式类型参数)的数量和参数的编译时类型来确定将被调用的方法的签名 (§15.12.2)。如果要调用的方法是实例方法,则将在运行时使用动态方法查找 (§15.12.4) 确定要调用的实际方法。

在您的示例中,Java 编译器确定与您调用方法的实例的编译类型最接近的匹配项。在这种情况下:

A.method(AX)

最接近的方法来自类型 A,带有签名 。在运行时,动态调度是在实际类型的 A(AX 的实例)上执行的,因此这是实际调用的方法:A.method(A)

AX.method(A)

答案 2

我将以更简单的方式澄清它。看看你什么时候用超类引用制作子类对象,就像你在这里所做的那样。

始终有一件事要记住,当您使用超类引用调用时,无论对象是子类,它都会转到超类,检查具有此名称的方法以及正确的签名是否存在。

现在如果它能找到它,那么它会检查它是否被覆盖??如果是,那么它将转到子类方法,就像这里一样。另一个明智的做法是,它将执行相同的超类方法。

我可以给你一个例子...只是隐藏

public int method(A a) {
        return 3;
    }

方法和检查你的答案,你会得到1 2 1 2,为什么因为它给予参考的第一优先级。因为你覆盖了它,而不是称呼它,所以它给了3..!!希望它很大,但很容易理解。快乐学习


推荐