请参考下面的Java代码:
class Base{
Base(){
System.out.println("Base Constructor");
method();
}
void method(){}
}
class Derived extends Base{
int var = 2;
Derived(){
System.out.println("Derived Constructor");
}
@Override
void method(){
System.out.println("var = "+var);
}
}
class Test2{
public static void main(String[] args) {
Derived b = new Derived();
}
}
看到的输出是:
Base Constructor
var = 0
Derived Constructor
我认为 var = 0 发生是因为派生对象已半初始化;类似于什么乔恩斯基特在这里说 https://stackoverflow.com/questions/1511822/java-call-overridden-method-implicitly/1511836#1511836
我的问题是:
如果尚未创建派生类对象,为什么会调用重写的方法?
var 在什么时间点被赋值为 0?
是否有任何需要这种行为的用例?
The Derived
object has已创建 - 只是构造函数尚未运行。在 Java 中,对象的类型在创建后就永远不会改变,这发生在所有构造函数运行之前。
var
在运行构造函数之前,作为创建对象过程的一部分,被分配默认值 0。基本上,类型引用被设置,并且表示对象的其余内存被擦除为零(从概念上讲,无论如何 - 作为垃圾收集的一部分,它之前可能已经被擦除为零)
这种行为至少会带来一致性,但也可能会很痛苦。就一致性而言,假设您有一个可变基类的只读子类。基类可能有一个isMutable()
属性实际上默认为 true - 但子类覆盖它以始终返回 false。如果对象在子类构造函数运行之前是可变的,但在运行之后就不可变,那就很奇怪了。另一方面,它是确实奇怪的是,在类的构造函数运行之前,您最终在类中运行代码:(
一些指导方针:
尽量不要在构造函数中做太多工作。避免这种情况的一种方法是在静态方法中进行工作,然后使静态方法的最后部分成为仅设置字段的构造函数调用。当然,这意味着您在执行工作时不会获得多态性的好处 - 但在构造函数调用中这样做无论如何都是危险的。
尽力避免在构造函数期间调用非最终方法 - 这很可能会导致混乱。记录任何真正调用您的方法have使very显然,这样任何覆盖它们的人都知道它们将在初始化完成之前被调用。
如果你必须在构造过程中调用一个方法,那就是usually之后调用它就不合适了。如果是这种情况,请记录下来并尝试在名称中注明。
首先尽量不要过度使用继承——只有当您有一个从超类派生的子类而不是 Object 时,这才会成为问题:) 继承设计是很棘手的。
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)