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()方法!

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

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值