Abh*_*bhi 12 java inheritance constructor
请参考下面的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();
}
}
Run Code Online (Sandbox Code Playgroud)
看到的输出是:
Base Constructor
var = 0
Derived Constructor
Run Code Online (Sandbox Code Playgroud)
我认为var = 0的发生是因为Derived对象是半初始化的; 类似于Jon Skeet在这里所说的
我的问题是:
如果尚未创建Derived类对象,为什么会调用重写的方法?
在什么时间点,var赋值为0?
是否存在需要此类行为的用例?
Jon*_*eet 12
该Derived对象已被创建-它只是在构造函数尚未运行.在创建它之后,对象的类型永远不会在Java中更改,这在所有构造函数运行之前发生.
var在构造函数运行之前,为创建对象的过程分配默认值0.基本上,类型引用被设置并且表示对象的其余内存被擦除为零(概念上,无论如何 - 它可能已经被擦除为零,作为垃圾收集的一部分)
这种行为至少会导致一致性,但这可能是一种痛苦.就一致性而言,假设您有一个可变基类的只读子类.基类可能有一个isMutable()有效默认为true 的属性 - 但是子类将其重写为始终返回false.在子类构造函数运行之前,对象是可变的是奇怪的,但之后是不可变的.另一方面,在您运行该类的构造函数之前最终在类中运行代码的情况下,这绝对是奇怪的:(
一些指导原则:
尽量不要在构造函数中做太多工作.避免这种情况的一种方法是在静态方法中工作,然后使静态方法的最后部分成为构造函数调用,它只是设置字段.当然,这意味着当你正在做工作时,你不会从多态中获益 - 但是在构造函数调用中这样做无论如何都是危险的.
在构造函数期间尽量避免调用非final方法 - 这很可能会引起混淆.文档的任何方法调用你真的必须做出非常清楚,让任何人都重写他们知道,初始化完成之前,他们将被调用.
如果你必须在施工期间调用一个方法,那么通常不适合在之后调用它.如果是这种情况,请记录并尝试在名称中指明它.
尽量不要过度使用继承 - 当你从一个非Object类以外的超类派生的子类时,这只会成为一个问题.继承的设计很棘手.
如果尚未创建Derived类对象,为什么要调用重写的方法?
Derived类构造函数隐式调用Base类构造函数作为第一条语句。Base类构造函数调用method(),它调用类中的重写实现,Derived因为这是正在创建其对象的类。method()在Derived课堂var上,此时该值被视为0。
var在什么时间点分配值为0?
varint在Derived调用类的构造方法之前,已为类型指定默认值,即0 。它被分配值2 之后的隐性超类构造器调用完成和前文中陈述Derived类的构造函数开始执行。
是否有任何需要这种行为的用例?
它通常是一个坏主意,使用非final无private方法在非的构造函数/初始化final类。原因在您的代码中显而易见。如果正在创建的对象是子类实例,则这些方法可能会产生意外的结果。