构造器是用来做什么的?当然是用来构造对象的!但是构造对象的过程你了解吗?
构造对象过程中的坑
请阅读以下代码,并模拟其输出的值。
1 | class Father { |
1 | Output:~ |
程序很正常的输出了两次200,然而当我们用一个子类去继承时:
1 | class Child extends Father { |
结果让人意外!
1 | Output:~ |
这里涉及到继承和多态,当我们在构造对象的时候,消息的顺序一般是从自身向父类发送,逐层压入栈,然后顺序出栈构造(栈只是顺序,并不代表真正执行的结构)。
父Static域 -> 子Static域 -> 父构造器涉及的域 -> 父构造器 -> 子构造器涉及的域 -> 子构造器 ……
而如果构造对象时,父类执行了一些(可能会)被子类重写的方法,则会出现上述不可预知的错误。原因在于,当我们执行到“父构造器”时,此时调用了draw()
方法,由于我们对象时Child类型的,编译器则会根据多态(运行时绑定)寻找到被子类重写(Override)的方法,但是此时还未初始化子类的value
域,故而输出错误的值。
好在此时编译器为我们赋予了类私有域一个默认值(0、null),否则我们的程序就要空指针了!
所以,在构造对象(构造器)时,尽量不要调用非final的方法(private方法是隐式的final方法),否则会出现不可预知的问题,导致对象构建不完全。
当然,构造器还有一些其他的特性,比如被private
修饰时,若无其他的构造器,则无法构建对象,自然也无法被继承。这里就不一一展开了,有兴趣的朋友请自行阅读《Thinking In Java》。