一个多态实例 select 它的方法是怎样的?

How does a polymorphic instance select its methods?

我无法理解这段代码的行为。 a定义为A,c定义为C。 然后,在publicclass的最后,a = c。 当 a 调用 display() 方法时,它到达它的 C 版本。 但是当 a 调用 f() 它只到达 A 版本时,尽管第一个参数(字节和长)比浮点更符合长。

这是书中的练习,但解释很少,或者根本不存在。

class A{
    public void display(){
        System.out.println("I am an A ");
    }

    public void f(double x){
        System.out.println("A.f(double = " + x + ") ");
    }
}

class C extends A{
    public void display(){
        System.out.println("I am a C ");}

    public void f(long q){
        System.out.println("C.f(long = " + q + ") ");}
    }


public class PolySurStack{
    public static void main(String Args[]){
        byte bb =1; long q = 4; float x = 5.f;

        System.out.println(" ** A **");
        A a = new A(); a.display();
        a.f(bb); a.f(x);

        System.out.println();
        System.out.println(" ** C **");
        C c = new C(); c.display();
        c.f(bb); c.f(q); c.f(x);
        System.out.println();
        a = c; a.display();
        a.f(bb); a.f(q); a.f(x);
    }
} 

当您调用 a.f(bb)a.f(q)a.f(x) 时,编译器可以选择的唯一方法签名是 class A 中定义的方法签名(或 A 的任何超级 class),因为 a 是类型 A.

的引用变量

因此,只考虑public void f(double x)。为了使 public void f(long q) 成为重载决议的候选者,您必须在调用 f() 之前将 a 强制转换为键入 C,因为只有 class C 定义具有该签名的方法。

要理解的重要一点是方法重载解析发生在编译时。只有您为其调用方法的引用变量的编译时类型决定了哪些方法签名是方法重载解析的候选者,以及将选择哪个候选者。

编译器选择的方法取决于声明的类型,而不是运行时类型。
声明为变量 A 的第一个系列只能调用 A 方法(无论实例化为 A 的运行时类型仅派生自 Object):

A a = new A(); 
a.f(bb); a.f(x);

对于第二个系列,由于 C 是一个 A,因此编译器会绑定与调用匹配的最具体参数的方法,因此编译器可以绑定任何 public 方法其中:

C c = new C(); 
c.f(bb); c.f(q); c.f(x);   

但是在最后一段可能会质疑你自己的代码中,aC 引用为运行时对象,但将 A 引用为声明类型:

A a = new A(); 
// ...
a = c; 
a.f(bb); a.f(q); a.f(x);

因此只能调用 A 中定义的方法。

我会尽量澄清@eran 的答案,以便您理解。

一个 subclass 拥有它的 superclass 的所有方法,然后可能还有更多。您有一个 A 类型的变量,其中存储了一个 C 类型的对象。 C 具有 class A 中定义的所有方法,还有一个附加方法 f(long q)A 不知道这个新方法,所以由于您将对象存储在 A 的变量中,您不能调用 f(long q).

可以 但是调用 display() 因为它是在 A 中定义的,但它仍然是执行它的 C 对象.

我刚在另一个论坛上找到这个:

重载:(相同的函数名称但不同的签名)

  1. 在同一个 class 中具有相同名称但参数不同的两个或多个方法称为重载。

  2. 当你想扩展功能时使用重载。

  3. 重载被称为编译时多态性

覆盖:(相同的函数名称但相同的签名)

  1. 两个或多个方法在父 class 和子 class 中具有相同的方法名称和相同的参数,称为覆盖。

  2. 当你想重用现有的功能时使用覆盖。

  3. 覆盖被称为运行时间多态性

所以我的问题的答案似乎是覆盖分辨率(如 display() )发生在 运行 时间(此处在 a = c 之后),而重载分辨率(如 f() )发生在编译时,当 a 仍然是 A.

我觉得。

我也找到了这个页面:https://beginnersbook.com/2013/04/runtime-compile-time-polymorphism/

要清楚且与该主题高度相关。