使用超类引用调用重载的继承方法

2022-09-02 23:08:17

我不理解Java的这种行为。我有两个类:

class C1 {
    public void m1(double num) {
        System.out.println("Inside C1.m1(): " + num);
    }
}

class C2 extends C1 {
    public void m1(int num) {
        System.out.println("Inside C2.m1(): " + num);
    }
}

这是我的主要:

public class Main {

    public static void main(String[] args) {
        C1 c = new C2();
        c.m1(10);
    }
}

结果是:

Inside C1.m1(): 10.0

当我期望:

Inside C2.m1(): 10

另外,当我尝试完成代码语法时,我发现了这个:

Enter image description here

C2级的另一个m1在哪里?

我还检查了我的Main.class的字节码,我看到了这个:

Compiled from "Main.java"
public class com.company.Main {
  public com.company.Main();
    Code:
       0: aload_0
       1: invokespecial #1                  // Method java/lang/Object."<init>":()V
       4: return

  public static void main(java.lang.String[]);
    Code:
       0: new           #2                  // class com/company/C2
       3: dup
       4: invokespecial #3                  // Method com/company/C2."<init>":()V
       7: astore_1
       8: aload_1
       9: ldc2_w        #4                  // double 10.0d
      12: invokevirtual #6                  // Method com/company/C1.m1:(D)V
      15: return
}

字节码告诉我它将调用C1.m1(D)V(第12行)。

为什么使用C1的方法?我试图理解这种行为。


答案 1

您命名的两个方法没有相同的签名;超类中的那个取一个,子类中的那个取一个。这意味着编译器将根据变量的编译时类型选择要调用的方法签名,即 ,并将调用 。因为在运行时,类没有 的重写版本,所以调用 from 的版本。m1doubleintC1m1(double)C2m1(double)C1

规则是方法签名在编译时基于编译时类型进行计算;方法调用在运行时基于匹配的签名进行调度


答案 2

这是因为参数。您调用的方法是具有双精度参数的方法。C2 内部的 m1 不会覆盖此内容,而是会覆盖它。

如果要在 C2 中调用 m1,则必须强制转换引用,以便编译器接受您正在执行的操作。