Java 多态的一道例题

参考https://blog.csdn.net/jerry191/article/details/51870890?utm_source=blogxgwz3

一、题目

class A {  

  public String show(D obj){  

      return ("A and D");  

  }  

  public String show(A obj){  

      return ("A and A");  

  }  

}  

class B extends A{  

  public String show(B obj){  

      return ("B and B");  

  }  

  public String show(A obj){  

      return ("B and A");  

  }  

}  

class C extends B{}  

class D extends B{}  

 

 

public class Testduotai {

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));  

  System.out.println("10"+d.show(a1)); 

  System.out.println("11"+d.show(a2)); 

  System.out.println("11"+d.show(b)); 

  System.out.println("12"+d.show(c)); 

  

}

  

}

二、运行结果

1A and A

2A and A

3A and D

4B and A

5B and A

6A and D

7B and B

8B and B

9A and D

10B and A

11B and A

11B and B

12B and B

三、分析

这个题目主要考察重写、重构、继承、多态(向上转型)中方法的访问规则

1、分析一下ABCD四个类的继承关系,及AB中show方法的关系

(1)ABCD四个类的继承关系:

父------>子
A-->B-->C
A-->B-->D

(2)AB中show方法的关系:

重构关系:
A中的show D、show A 与 B中的show B
A中的show D 与 B中的show B、show A

重写关系:
A中的show A 与 B中的show A

在多态的访问规则中,单纯的重构不影响访问规则。
几个重构的方法选择哪个是由实参类型来决定的,实参和形参类型匹配上了,就调用该方法。
但重构可能会遇上实参向上转型变成形参类型的情况,这种情况很复杂,但要记住一点,如果对象本身是向上转型的,那么它只能访问子类的重写方法,不能访问子类的重构方法。

重写方法影响访问规则。
通过重写,继承的子类只会调用子类中重写的方法,而不会调用父类中原本的方法。
向上转型的对象正常是不能访问子类的方法的,重写的除外。经过向上转型的对象,可以调用子类中重写的方法,而不会调用父类中原本的方法。

但问题在于,如果方法和变量不重名的话,那么继承和多态的访问规则还比较清楚,但一旦加上了重名(方法的重构、重写,变量重名引出的动态绑定机制),访问规则就特别混乱。

这个题目仅仅针对方法的重构、重写,还没有属性重名的情况。

四、总结

1、经过向上转型的对象访问父类和子类的方法时的顺序


先 子类方法 后 父类方法,先 实参直接匹配形参 后 实参向上转型匹配形参。

向上转型的对象中只能访问子类中重写的方法,非重写的方法无法访问。

如果子类中有重写的方法,并且这个向上转型的对象调用的方法也存在实参向上转型匹配形参的情况,

访问顺序由先到后如下:


子类中经过重写且形参直接匹配实参的方法,(子类中重构的方法不可被向上转型的对象调用)

然后父类中形参直接匹配实参的方法(如果父类中有多个重构的方法,看实参和形参的匹配程度,完全一致 > 自动转换 > 强制转换)

再然后子类中重写且实参向上转型后可以匹配形参的方法,(子类中重构的方法不可被向上转型的对象调用)

最后父类中实参向上转型匹配形参的方法。(如果父类中有多个重构的方法,看实参和形参的匹配程度,完全一致 > 自动转换 > 强制转换)

注1:这里的子类和父类并不单单指两个类,可以是一长串互为子类父类的类,访问顺序就是先子类,后父类,后父类的父类……直到Object类


注2:这一套走下来没有符合的方法,则报错。

2、继承的访问规则


先子类后父类,
先子类直接匹配,后父类直接匹配。

五、具体分析

以序号4的输出为例,

System.out.println("4"+a2.show(b));

a2为向上转型,a2的编译类型是A,运行类型是B。b作为实参,类型为B,可能直接匹配上实参类型,也可能向上转型成A。

首先,最容易忽略的点,即使不考虑实参b,a2这个向上转型也不能访问子类中的重构方法,也就是B中的show B。

然后,访问顺序如下,

最先看的是,先子类、重写、实参直接匹配形参,B的show A,无法直接匹配,

然后是,父类、实参直接匹配形参,A的show A和show D,因为b的类型为B,也无法直接匹配

再然后是,子类、重写、实参向上转型匹配形参,B的show A,看一下能不能b向上转型成A,可以,就这个方法了,输出4B and A。

原文地址:https://www.cnblogs.com/lylhome/p/15795075.html