基类构造函数在Java中调用重写方法时派生类对象的状态
请参考下面的Java代码:基类构造函数在Java中调用重写方法时派生类对象的状态,java,inheritance,constructor,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
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是因为派生对象被半初始化;类似于什么
我的问题是:
如果还没有创建派生类对象,为什么要调用重写的方法
var在什么时间点赋值为0
是否存在需要此类行为的用例?
对象已经创建-只是构造函数还没有运行。在Java中,对象的类型在创建之后不会改变,这发生在所有构造函数运行之前派生的
在运行构造函数之前,作为创建对象过程的一部分,被指定默认值0。基本上,类型引用被设置,表示对象的其余内存被擦除为零(无论如何,从概念上讲,它可能已经被擦除为零,作为垃圾收集的一部分)var
- 这种行为至少会带来一致性,但也会带来痛苦。在一致性方面,假设您有一个可变基类的只读子类。基类可能有一个
属性,该属性实际上默认为true,但子类将其重写以始终返回false。在子类构造函数运行之前,对象是可变的,但之后是不可变的,这是很奇怪的。另一方面,当您在类的构造函数运行之前在类中运行代码时,这种情况肯定很奇怪:(isMutable()
- 尽量不要在构造函数中做太多的工作。避免这种情况的一种方法是在静态方法中工作,然后使静态方法的最后部分成为一个只设置字段的构造函数调用。当然,这意味着您在工作时不会得到多态性的好处,但在构造函数调用中这样做是危险的反正是我们
- 在构造过程中尽量避免调用非final方法-这很可能会造成混乱。请非常清楚地记录您必须进行的任何方法调用,以便覆盖它们的任何人都知道它们将在初始化完成之前被调用
- 如果您必须在构造过程中调用某个方法,那么通常不适合在之后调用它。如果是这种情况,请记录它并尝试在名称中指明它
- 首先,尽量不要过度使用继承-只有当您有一个子类派生自除Object:)以外的超类时,这才会成为一个问题。为继承设计是很棘手的
- 超类构造函数总是在子类构造函数之前隐式/显式调用
- 来自构造函数的方法调用与任何其他方法调用一样;如果方法是非final的,则调用是虚拟调用,这意味着要调用的方法实现是与对象的运行时类型关联的方法实现
- 在执行构造函数之前,所有数据成员都会自动初始化为默认值(0表示数字原语,null表示对象,false表示布尔值)
Derived
类构造函数隐式调用Base
类构造函数作为第一条语句Base
class构造函数调用method()
,该构造函数调用Derived
类中被重写的实现,因为该类是正在创建其对象的类method()
在Derived
类中,此时将var
视为0
在什么时间点分配var
值0
var
被指定为int
类型的默认值,即在调用Derived
类的构造函数之前为0。在隐式超类构造函数调用完成之后和派生的类的构造函数中的语句开始执行之前,它被赋值为2
是否存在这样的用例
行为是需要的吗
在非
final
类的构造函数/初始值设定项中使用非final
非private
方法通常是个坏主意。原因在您的代码中很明显。如果正在创建的对象是子类实例,则方法可能会给出意想不到的结果。注意,这与C++不同,在该类型中,当对象正在构建时,类型会发生变化,因此调用基类构造函数的虚方法不调用派生类的重写。同样的事情