一道题解析面向对象的特征

public class TestDT {

    public static void main(String[] args) {
        A aa = new A();
        A ab = new B();
        B b = new B();
        C c = new C();
        D d = new D();
        System.out.println(aa.run(b));// 1, A & A
        System.out.println(aa.run(c));// 2, A & A
        System.out.println(aa.run(d));// 3, A & D

        System.out.println(ab.run(b)); // 4, B & A
        System.out.println(ab.run(c));// 5, B & A
        System.out.println(ab.run(d));// 6, A & D

        System.out.println(b.run(b));// 7, B & B
        System.out.println(b.run(c));// 8, B & B
        System.out.println(b.run(d));// 9, A & D
    }
}
class A {
    public String run(D obj) {
        return ("A & D");
    }

    public String run(A obj) {
        return ("A & A");
    }
}

class B extends A {
    public String run(B obj) {
        return ("B & B");
    }
    public String run(A obj) {
        return ("B & A");
    }

}
class C extends B {
}
class D extends B {
}

关于上面所有注释答案的解释其实就一个核心秘笈,多态是对象在不同时刻表现出来的多种状态,是一种编译时期状态和运行时期状态不一致的现象。我们在编写或者分析代码时记住如下口诀:
成员变量:编译看左,运行看左(因为无法重写);
成员方法:编译看左,运行看右(因为普通成员方法可以重写,变量不可以);
静态方法:编译看左,运行看左(因为属于类);
意思是当父类变量引用子类对象时(Base base = new Child();),在这个引用变量 base 指向的对象中他的成员变量和静态方法与父类是一致的,他的非静态方法在编译时是与父类一致的,运行时却与子类一致(发生了复写)。所以有了上面的口诀我们很容易分析出执行结果:

注释1中 aa 在编译时取决于左边 A 的类型,所以包含了参数为 A、D 的 run 方法,而运行时传递给 run 方法的参数类型为 A,所以执行了 A 类中参数为 A 类型的 run 方法。

注释2中 aa 在编译时取决于左边 A 的类型,所以包含了参数为 A、D 的 run 方法,而运行时传递给 run 方法的参数类型为 C,而此时只支持参数为 A、D 的 run 方法,而 C 又继承自 B,B 继承自 A,所以执行了 A 类中参数为 A 类型的 run 方法。

注释3中 aa 在编译时取决于左边 A 的类型,所以包含了参数为 A、D 的 run 方法,而运行时传递给 run 方法的参数类型为 D,而此时恰巧支持参数为 A、D 的 run 方法,所以直接执行了 A 类中参数为 D 类型的 run 方法。

注释4中 ab 在编译时取决于左边 A 的类型,运行时为右边 B 的类型,所以编译时包含了参数为 A、D 的 run 方法,而运行时传递给 run 方法的参数类型为 B,所以对应的方法为 A 类中参数为 A 类型的 run 方法,而由于 ab 在运行时右侧的 B 类中重写了 A 类中参数为 A 类型的 run 方法,所以运行时最终执行了 B 类中重写的参数为 A 类型的 run 方法(所以类 B 中参数为 B 的 run 方法其实是 B 类特有的重载方法,而不是重写方法)。

注释5中 ab 在编译时取决于左边 A 的类型,运行时为右边 B 的类型,所以编译时包含了参数为 A、D 的 run 方法,而运行时传递给 run 方法的参数类型为 C,C 又最终继承自 A,所以对应的方法为 A 类中参数为 A 类型的 run 方法,而由于 ab 在运行时右侧的 B 类中重写了 A 类中参数为 A 类型的 run 方法,所以运行时最终执行了 B 类中重写的参数为 A 类型的 run 方法。

注释6中 ab 在编译时取决于左边 A 的类型,运行时为右边 B 的类型,所以编译时包含了参数为 A、D 的 run 方法,而运行时传递给 run 方法的参数类型为 D,所以对应的方法为 A 类中参数为 D 类型的 run 方法。

注释7中 b 在编译时取决于左边 B 的类型,运行时为右边 B 的类型,所以编译时包含了参数为 A、B、D 的 run 方法,而运行时传递给 run 方法的参数类型为 B,所以对应的方法为 B 类中参数为 B 类型的 run 方法(B 在编译时已经继承了 A 的方法)。

注释8中 b 在编译时取决于左边 B 的类型,运行时为右边 B 的类型,所以编译时包含了参数为 A、B、D 的 run 方法,而运行时传递给 run 方法的参数类型为 C,而 C 的第一父类是 B,此时恰巧 B 中有支持参数为 B 的 run 方法(所以不用再往上找),所以对应的方法为 B 类中参数为 B 类型的 run 方法。

注释9中 b 在编译时取决于左边 B 的类型,运行时为右边 B 的类型,所以编译时包含了参数为 A、B、D 的 run 方法,而运行时传递给 run 方法的参数类型为 D,所以对应的方法为 B 类中从 A 类继承来的参数为 D 类型的 run 方法。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值