Java 多态之方法调用顺序

本文例子取于<深刻理解java多态性><java提升篇(四)-----理解java的三大特性之多态>,分析 Java 继承链方法调用优先级以及执行流程。html

本文至关因而我对上面两篇文章的理解。java

public class A {
    public String show(D obj) {
        return ("A and D");
    }

    public String show(A obj) {
        return ("A and A");
    } 
}

public class B extends A{
    public String show(B obj){
        return ("B and B");
    }
    
    public String show(A obj){
        return ("B and A");
    } 
}

public class C extends B{}

public class D extends B{}

public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        
        System.out.println("(1)"+a1.show(b));  
        System.out.println("(2)"+a1.show(c));  
        System.out.println("(3)"+a1.show(d));   
        System.out.println("(4)"+a2.show(b));   
        System.out.println("(5)"+a2.show(c));   
        System.out.println("(6)"+a2.show(d));   
        System.out.println("(7)"+b.show(b));     
        System.out.println("(8)"+b.show(c));   
        System.out.println("(9)"+b.show(d)); 

    }
}

输出结果:this

(1)A and A
(2)A and A
(3)A and D
(4)B and A
(5)B and A
(6)A and D
(7)B and B
(8)B and B
(9)A and D

根据 Java 多态机制,继承链中对象方法的调用存在一个优先级:.net

this.method(O) -> super.method(O) -> this.method((super)O) -> super.method((super)O)code

上面两篇文章中都提到多态机制遵循的规则能够归纳为当超类对象引用变量引用子类对象时,被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法,可是这个被调用的方法必须是在超类中定义过的。htm

以上面的例子举例,A a = new B(); 就是超类对象引用变量 a 引用了子类 B 的对象,最终由 B 来决定调用谁的成员方法,但前提是这个方法即 show 方法必须在超类中定义过的。对象

在这里我把这两句话从新排序并解读:blog

  • 当超类对象引用变量引用子类对象时,首先这个被调用的方法必须在超类中定义过 = 根据上面继承链对象方法调用优先级能够在超类中找到这个方法
  • 被引用对象的类型而不是引用变量的类型决定了调用谁的成员方法 = 判断子类是否重写了该方法,若是重写了直接调用子类的方法

简单来讲就是先根据优先级肯定目标方法,而后根据多态机制遵循的规则来决定调用子类仍是超类的成员方法。排序


下面开始分析例子中的九种状况。继承

(1)(2)(3) 的例子都不是超类对象引用变量引用子类对象的状况,因此在超类中找到方法后直接调用便可。

(1) a1.show(b)

  • 根据优先级第一级 this.method(O) 可改为 A.show(B) ,即要在 A 中 寻找方法 show(B),因为 A 中没有 show(B) 的方法,因此进入第二级 super.method(O) 。
  • 由于 A 除了 Object 以外没有父类且 Object 中确定没有 show 方法,因此进入第三级 this.method((super)O) 。
  • B 的父类是 A 因此目标是找 A.show(A) ,而后 A 中找到了 show(A) 方法并直接调用,返回 " A and A "。

(2) a1.show(c)

  • 进入第三级 this.method((super)O) 以前跟 (1) 同样。
  • C 的父类是 B,并无在 A 中找到 show(B) 方法,因此会根据 C 的继承链继续向上找 B 的父类 A ,而后寻找 A.show(A) ,因此最终结果跟 (1) 同样是 " A and A "。

(3) a1.show(d)

  • 直接根据第一级便可找到目标方法 A.show(D) 并执行获得 " A and D "。

(4)(5)(6) 都是超类对象引用变量引用子类对象的状况,因此在超类中找到方法后还要根据多态机制规则决定执行子类仍是超类的方法。

(4) a2.show(b)

  • 根据优先级第一级在 A 中找不到 show(B) ,因此进入第二级。
  • 由于 A 除了 Object 以外没有父类且 Object 中确定没有 show 方法,因此进入第三级 。
  • 根据第三级在 A 中找到了 show(A) ,而后根据多态机制规则因为子类 B 重写了 show(A) 方法,因此最终调用的是 B.show(a) ,获得结果是 " B and A "。

(5) a2.show(c)

  • 进入第三级以前跟 (4) 同样。
  • 根据第三级在 A 中没有找到 show(B) ,因此会根据 B 的继承链向上找 B 的父类 A ,并在 A 中找到了 show(A) ,而后根据多态机制规则因为子类 B 重写了 show(A) 方法,因此最终调用的是 B.show(a) ,获得结果是 " B and A "。

(6)a2.show(d)

  • 直接根据第一级便可找到目标方法 A.show(D) ,而后根据多态机制规则因为子类 B 没有重写 show(A) 方法,因此执行超类方法 A.show(D) ,获得结果为 " A and D "。

至于(7)(8)(9)根据上面就能够推导出来。