你真的清楚多态中究竟是哪个实例调用哪个方法吗?

本文深入探讨Java中的多态概念,详细解析多态继承中子类方法的调用原则,并通过具体实例展示了不同引用类型和实际对象类型组合下方法调用的行为。

接上文Java的三大特性之封装、继承和多态详解,这里我们研究一下多态的应用。

【1】多态继承中子类方法的调用遵循原则

① 当引用类型与实际对象一致时,调用方法首先从自身方法匹配;然后从父类寻找。

② 当引用类型为实际对象的父类时:

  • 2.1 如果实际对象类型与实参类型一致:

    • 先从父类找参数类型一致的方法,如果实际对象重写了父类方法,那么调用实际对象重写的方法;
    • 否则,从父类找调用参数为引用类型的方法(同理,如果实际对象重新了父类方法则调用实际对象重写的方法)。
  • 2.2如果实际对象类型与实参类型不一致:

    • 从引用类找实参类型的方法,如果子类实际对象重写了该方法则调用实际对象的方法;
    • 否则尝试去引用类找参数类型为实参最近父类的方法(如果子类重写了该方法则调用子类实际对象的方法);

可达性原则:引用类型到目标方法必须可达,比如子类拥有父类的方法,但是父类引用变量不可达子类自定义方法。

参数类型一致原则:在可达方法后,优先考虑参数类型一致的。

子类重写优先原则:如果子类(实际对象)重写了该方法,则优先考虑重写方法

继承链中对象方法的调用优先级:this.show(O)--super.show(O)--this.show((super)O)--super.show((super)O)。即,首先是本类且参数不用转型的,其次是父类但是参数不用转型的,然后是本类但是参数需要转型,最后才是父类且参数需要转型的。


【2】测试实例

类继承结构

public class A {
	
	public String show(A obj){
		return("A and A");
	}
	
	public String show(D obj){
		return("A and D");
	}
	
}
 class B extends A{
	//重写了父类的方法
	 public String show(A obj){
		 return("B and A");
	 }
	 
	public String show(B obj){
		return("B and B");
	}
}
class C extends B{
	public String show(C obj){
		return("C and C");
	}
	
} 
class D extends B{

	//重写了父类的方法
	public String show(D obj){
		return("D and D");
	}
}



测试代码

public class ClassTest {	
	public static void main(String[] args) {
		
		A a1 = new A();
		A a2 = new B();
		B b = new B();
		C c = new C();
		B c2 = new C();
		D d = new D();
		B d2 = new D();
		
		
		System.out.println(a1.show(b));
		//1 A and A 
		System.out.println(a1.show(c));
		//2 A and A 
		System.out.println(a1.show(d));
		//3 A and D  
		System.out.println(a2.show(a1));
		//4 B and A 
		
		System.out.println(a2.show(b));
		//5 B and A  
		
		System.out.println(a2.show(c));
		//6 B and A 
		
		System.out.println(a2.show(d));
		//7 A and D  
		
		System.out.println(b.show(a1));
		//8  B and A  
		System.out.println(b.show(b));
		//9  B and B  
		System.out.println(b.show(c));
		//10  B and B  
		System.out.println(b.show(d));
		//11  A and D  
		
		System.out.println(c2.show(a1));
		//12 B and A  
		System.out.println(c2.show(b));
		//13 B and B  
		System.out.println(c2.show(c));
		//14 B and B  
		System.out.println(c2.show(d));
		//15 A and D  
		
		System.out.println(d2.show(a1));
		//16 B and A  
		System.out.println(d2.show(b));
		//17 B and B  
		System.out.println(d2.show(c));
		//18 B and B  
		System.out.println(d2.show(d));
		//19 D and D  
	
	}

}

【3】结果分析

① 引用类型与实际对象一致,自身是父类

1.a1.show(b)

A and A 实际对象与引用类型一致,当然从自身找,自身找不到再从父类找。自身无与实参对应的参数方法,则查参数类型为实参父类的方法。

2.a1.show(c)

A and A 同1

3.a1.show(d)

A and D 实际对象与引用类型一致,当然从自身找,自身找不到再从父类找。自身有与实参类型一致的参数方法,则首先考虑。

② 引用类型为实际对象的父类

分析: 引用类型为实际对象的父类,根据参数类型一致原则与引用可达原则,先去父类找方法参数类型与实参一致的方法。如果找到方法,根据子类重写优先原则尝试去子类找重写方法。

如果子类没有重写方法,则调用父类的与实参类型一致的参数方法。

如果父类没有与实参类型一致的参数方法,则找参数类型为实参父类的方法(同样这里应用了子类重写优先原则)。

4.a2.show(a1)

B and A

5.a2.show(b)

B and A ,引用类型为A,实际对象为B,参数类型为B。首先从引用类A找方法参数类型为B的方法,没有则找方法参数为其父类A的方法,找到后判断子类实际对象B是否重写了该方法。

6.a2.show(c)

B and A

7.a2.show(d)

A and D

③ 引用类型与实际对象一致,自身是子类

分析:

  • ① 首先从自身找方法参数类型与实参类型一致的方法;
  • ② 从自身找方法参数是实参类型父类的方法;
  • ③ 从父类找方法参数与实参类型一致的方法;
  • ④ 从父类找方法参数数实参类型父类的方法;

8.b.show(a1)

B and A

9.b.show(b)

B and B

10.b.show(c)

B and B

11.b.show(d)

A and D ,自身没有参数为D的方法,但是父类有哦

12.c2.show(a1)

B and A 引用变量类型为实际对象的父类-实参与形参类型一致–实参非实际对象–类型一致优先

13.c2.show(b)

B and B 引用类为B,B自身有方法参数类型为B的方法。

14.c2.show(c)

B and B 引用类型为B,实际类型为C,引用类型为实际对象的父类。引用类B并没有一个方法参数类型为C的方法,B调用不了子类C的show©方法。

15.c2.show(d)

A and D ,应用类为B,实际对象为C。引用类没有方法参数为D的方法,转而去父类A找。

16.d2.show(a1)

B and A 引用类为B,实际对象为D。引用类B有方法参数类型为A的方法。

17.d2.show(b)

B and B 引用类为B,实际对象为D。引用类B有方法参数类型为B的方法。

18.d2.show(c)

B and B 引用类为B,实际对象为D。引用类B没有方法参数类型为C的方法,但是有方法参数类型为B的方法。

19.d2.show(d)

D and D 引用类为B,实际对象为D,实参类型为D;这里D继承B继承A,根据重写优先原则,这里找到方法参数类型为D的方法后一路往下找到实际对象D的show(D obj)方法。

评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

流烟默

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值