例如,
Subclass extends ParentClass {
private String subclassField;
Subclass() {
// it's illegal
super(subclassField);
}
}
这引入了编译错误“在调用构造函数时无法引用实例字段”。
StackOverflow中关于此场景的类似问题的一些答案转到“因为当前实例仍在构建中”或“尚未在堆中创建的实例”。
然而,令人困惑的是, 在超类构造函数中,可以调用可重写的成员方法,这些方法可以访问子类的当前实例的字段。它在Java中没问题。
我的查询是
在实例构造的过程中,哪个时刻可以引用子类的字段?
“在调用构造函数时不能引用实例字段”背后的基本原理是什么,而在超类构造函数中调用可重写的方法是可以的?
答案 0 :(得分:3)
在实例构造的过程中,从哪个时刻可以引用子类的字段?
从完成对超类构造函数的调用。请记住,在此之前,实例字段无论如何都只有默认值 - 即使您在它们上使用了初始化程序,或实例初始化块;在这两种情况下,执行该操作的代码都插入到类的构造函数中,在超类构造函数调用之后。考虑这对类:
class ParentClass {
ParentClass(String s) {
}
}
class Subclass extends ParentClass {
private String subclassField = "init";
Subclass() {
super("bar");
}
}
如果我们通过Subclass
查看javap -c Subclass
的字节码,我们会看到:
class Subclass extends ParentClass { Subclass(); Code: 0: aload_0 1: ldc #1 // String bar 3: invokespecial #2 // Method ParentClass."":(Ljava/lang/String;)V 6: aload_0 7: ldc #3 // String init 9: putfield #4 // Field subclassField:Ljava/lang/String; 12: return }
请注意,我们编写了我们的代码,好像我们这样写了:
class Subclass extends ParentClass {
private String subclassField;
Subclass() {
super("bar");
this.subclassField = "init"; // *** Note this moved
}
}
(是的,如果你很好奇,如果有多个构建函数,那么代码重复。)
在调用构造函数时“无法引用实例字段”背后的基本原理是什么,而在超类构造函数中调用可覆盖的方法是否合适?
你必须问詹姆斯戈斯林。但是考虑到与实例字段不同,实例方法在超类构造函数调用之前具有有用的值,实际上在构造期间使用方法有时非常有用。但是,使用可重写的方法是不好的做法;您在施工期间(直接或间接)使用的任何方法应该是最终的或私人的(例如,实际上是最终的)。编译器不会为您做出这种区分;也许如果现在正在编写规则,那就可以了。