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

Rob*_*ert 17 java oop syntax inheritance overloading

我不明白这种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);
    }
}
Run Code Online (Sandbox Code Playgroud)

这是我的主要内容:

public class Main {

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

结果是:

Inside C1.m1(): 10.0
Run Code Online (Sandbox Code Playgroud)

当我预料到:

Inside C2.m1(): 10
Run Code Online (Sandbox Code Playgroud)

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

在此输入图像描述

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
}
Run Code Online (Sandbox Code Playgroud)

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

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

chr*_*ke- 16

你命名的两个方法m1没有相同的签名; 超类中的一个取一个double,而子类中的一个取一个int.这意味着编译器将根据变量的编译时类型选择要调用的方法签名,这将是C1,并且将调用m1(double).由于在运行时该类C2没有重写版本m1(double),因此C1调用了版本.

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


Dis*_*ubo 10

这是因为参数.您调用的方法是具有double参数的方法.C2内部的m1没有覆盖它,而是重载它.

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


CKi*_*ing 7

为什么你看到的输出的原因Inside C1.m1(): 10.0,而不是Inside C1.m1(): 10或者Inside C2.m1(): 10.0是因为:

  1. 你是不是覆盖方法m1C2.你是超负荷m1(doube)您从继承的方法C1m1(int)代替.
  2. C2课程现在有两种m1方法.一个inherited来自C1并且具有签名m1(double),一个被重载C2并且具有签名m1(int)
  3. 当编译器看到调用时c.m1(10),它会根据引用类型解析此调用.由于引用类型是C1,编译器将解析此调用m1(double)in C1.
  4. 在运行时,JVM将要解决的呼叫m1(double)C2这是从继承方法C1.(如第2点所述)

有两种m1(int)方法可以调用该方法:

((C2)c).m1(10);

要么

C2 c = new C2(); c.m1(10);


drR*_*rtz 6

Java对静态类型执行方法调度,并且您的变量c属于类型C1,因此m1(int)不可见,并且您将10被强制转换为double.