本Java代码中构造函数的顺序是什么?
这是代码,我定义了两个名为Father和Son的类,并在main函数中创建它们:
public class Test { public static void main(String[] args) { Father father = new Son(); } } class Father { private String name = "father"; public Father() { who(); tell(name); } public void who() { System.out.println("this is father"); } public void tell(String name) { System.out.println("this is " + name); } } class Son extends Father { private String name = "son"; public Son() { who(); tell(name); } public void who() { System.out.println("this is son"); } public void tell(String name) { System.out.println("this is " + name); } }
我得到了这样的输出:
this is son this is father this is son this is son
但我无法理解这是怎么发生的? 谁能告诉我为什么?
-
让我们从
Son
的构造函数开始。public Son() { super(); // implied who(); tell(name); }
-
父亲的构造函数被调用。
public Father() { who(); tell(name); }
-
因为
who()
被Son
所覆盖,所以将调用Son
的版本,打印“这是儿子”。 -
tell()
也被覆盖,但传入的值是Father.name
,打印“this is father”。 -
最后,在
Son
的构造函数中调用who()
和tell(name)
将分别打印出“this is son”和“this is son”。
以下是所谓的:
new Son() => Son._init => first every constructor calls super() Father._init Object._init who() => is overridden, so prints "son" tell(name) => name is private, so cannot be overridden => "father" who() => "son" tell(name) => "son"
要吸取的教训:
- 私有字段和方法是私有的。 不能被覆盖。
- 不要从可以被覆盖的构造函数中调用方法。 这可以调用半初始化类状态的方法(尽管不会发生在你的情况下)。
创建Son
实例时,将调用父类的构造函数(即Father()
); 这里调用了who()
方法,但它是你在Son
声明的重写版本,所以这里是你的第一行(其中String在方法中被硬编码)。
第二行来自于Father()
的tell(name)
,其中tell()
被覆盖但是name == "father"
因为调用来自Father
的构造函数,而name
是类Father
的private
字段。
Control返回Son()
构造函数,最后两行直接来自Son
类构造函数。
在Son()
之前调用Father()
Son()
。 隐式调用超类默认构造函数,我们这里不需要super()
语句。
而Father()
的构造函数中的who()
调用重写方法。
上面的代码特别是Bad Style(TM)。 😉
会发生什么:没有父实例,只有Son实例。 (然而,它与父亲兼容。)
Son构造函数调用父构造函数。 后者调用重写的(!)方法,因此永远不会调用Father.who和Father.tell! 在子构造函数完成之前(!)调用重写的方法。
我的建议:
- 如果在构造函数中调用方法,请将其设为final。 或者让全class决赛。 或者至少将被调用的方法设为私有。
- 永远不要覆盖构造函数中调用的方法。
- 如果您不得不违反上述建议,请写下有关您为什么这样做以及您希望发生什么的广泛评论。 编写unit testing以确保您的假设有效。