使用超类引用变量在Java子类对象中重载/覆盖方法

class A{ void m1(A a) {System.out.print("A");} } class B extends A{ void m1(B b) {System.out.print("B");} } class C extends B{ void m1(C c) {System.out.print("C");} } public class d { public static void main(String[] args) { A c1 = new C(); C c2 = new C();c1.m1(c2); }} 

此代码的输出为'A'

但如果我将A类修改为:

  class A{ void m1(C a) {System.out.print("A");} } 

那么输出是'C' 。 有人可以解释这段代码是如何工作的?

(通过对参数类型和实现使用相同的inheritance层次结构,您已经使它变得更加混乱。分离它们可能有助于在您的脑海中简化它。)

c1的类型是A 因此,在确定要调用哪个方法签名时,编译器只能查看在A声明的方法。

所以在第一种情况下,编译器将调用m1(A) ; 在第二种情况下,编译器将调用m1(C)

现在在第一种情况下, m1(A)方法永远不会被覆盖,因此实际上c1的执行时类型是无关紧要的。

在第二种情况下, m1(C)C覆盖,因此调用C的实现是因为c1的执行时类型是C

所以请记住:

  • 根据方法目标和参数表达式的编译时类型,在编译时确定重载分辨率(调用方法签名)
  • 该方法签名( 覆盖 )的实现基于执行时目标对象的实际类型。