Java构造方法链和动态绑定

构造方法可以调用重载的构造方法或它父类的构造方法。如果他们都没有被显示的调用,编译器就会自动的将super()作为构造方法的第一条语句!

如:

public MyConstruct() {
		
	}
	
	public MyConstruct() {
		super();
	}

以上两个构造方法是完全等价的,因为 当没有显示调用的时候,编译器会自动认为super()为构造函数的第一条语句。

public MyConstruct(int i) {
		
	}
	
	public MyConstruct(int i) {
		super();
	}

这两个构造方法也是等价的!


在任何情况下,构造一个类的实例时,将会调用沿着继承链的所有父类的构造方法。通俗的说就是在构造一个子类的对象时,子类构造方法会在完成自己的任务之前先调用父类的构造方法,如果父类又继承自其他类,那么父类在完成自己的任务之前也会先调用他的父类的构造方法,一直持续,直到最后一个类的构造方法被调用,这就是构造方法链。


下面通过一个实例来说明:

class Person{
	public Person() {
		System.out.println("Person");
	}
}

class Employee extends Person{
	public Employee() {
		this("Employee1");
		
		System.out.println("Employee2");
	}

	public Employee(String str) {
		System.out.println(str);
	}
}

public class Faculty extends Employee{
	
	public Faculty() {
		System.out.println("Faculty");
	}
	
	public static void main(String[] args) {
	
		new Faculty();
	}

}

程序的输出结果:


下面我们来解释一下为什么会如此这般的输出:

1:程序执行main()方法中的new Faculty();根据构造方法链原理,程序会去调用它的父类的构造方法,所以调用了public Employee(){},在执行之前又调用了Employee父类的构造函数即public Person();此时已经到了终点,所以第一条被打印的语句应该是Person类中的“Person”。

2:打印完“Person”之后,程序并没有结束,而是往回倒,回到了Employee中执行Employee中的逻辑代码,在Employee中我们可以发现第一句有个this关键字,这是显示调用本类中带参的构造函数的意思,所以程序直接跳到了public Employee(String s){XXX};这个构造函数中,所以打印Employee1,打印完之后再执行的public Employee(){}无参构造函数中的"Employee2"。

3:打印完Employee中的字符串之后,又回到了Faculty类,所以最后打印的是“Faculty”


动态绑定:

先看一个问题:

		Object o = new Car();
		System.out.println(o.toString());

程序是调用Object中的toString()方法呢?还是调用Car中的toString()方法呢?

我们先来看两个概念:声明类型和引用类型。

一个变量必须被声明为某种类型,变量的这个类型被称为声明类型,上述代码中的o的声明类型是Object;实际类型是被变量引用的对象的实际类,上述代码中o的实际类型为Car。


动态绑定的工作机制:假设对象o是类C1,C2,C3...Cn的实例,其中C1是C2的子类,C2是C3的子类...以此类推。如果对象o调用一个方法fun();那么java 虚拟机会依次在C1,C2,...Cn中查找方法fun();的实现,知道找到为止,一旦找到一个实现,就会停止查找然后调用这个第一次找到的实现。

下面通过一个示例来展示:

class People extends Object{
	@Override
	public String toString() {
		return "People";
	}
}

class Student extends People{
	@Override
	public String toString() {
		
		return "Student";
	}
}

class GraduateStudent extends Student{
	//这个方法中不对toString()方法进行重写
}
public class DynamicBindTest {

	public static void main(String[] args) {

		fun(new GraduateStudent());
		fun(new Student());
		fun(new People());
		fun(new Object());
	}

	/**
	 * 这个方法的类型是Object,所以通用类型都可以传进来
	 * @param obj
	 */
	public static void fun(Object obj){
		
		System.out.println(obj.toString());
	}
}

程序的输出结果为:


如此这般输出的原因:

1:fun(new GraduateStudent())执行时会调用fun()方法中的obj.toString()方法,GraduateStudent继承Student,Student继承People,People又继承Object,根据动态绑定的原理,会依次查询GraduateStudent->Student->People->Object中的toString()方法,一旦找到就立调用并停止查询,GraduateStudent类中没有实现toString()方法,所以到了Student类中,发现这个类中实现了toString()方法,程序马上调用,然后停止,即第一个输出的是Student类中的"Student"

2:执行fun(new Student())时同样的道理,依次寻找toString()方法,然后发现Student类中就实现了toString()方法,调用然后停止,即输出第二个也是Student类中的"Studnet"。

3:执行fun(new People())时也是同样的道理,输出的是people类中的"People"。

4:执行fun(new Object())时,输出的是Object类中的toString()方法!


到这里,这两个知识点就讲完了,切记不要混淆两个概念,构造方法链是一直往上找,找到最后的类进行执行,而动态绑定也是往上找,只不过一旦找到就立即调用并马上停止!

  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值