![](/img/trans.png)
[英]why does the subclass have to invoke the no args constructor in the super class?
[英]Why does the super constructor have to be called before fields can be accessed?
我的一个类继承自我使用的框架中的类。 超类在其构造函数中调用一个方法,我在自己的类中覆盖它。 该方法使用我想要在超级构造函数调用之前初始化的字段以避免NullPointerException。
有没有办法做到这一点?
这是一个综合测试场景,我希望在call
时, Child
c
不为null。
public class Test {
public static class Parent {
public Parent() {
super();
call();
}
// only called from parent constructor
public void call() {
System.out.println("Parent");
}
}
public static class Child extends Parent {
private Child c = this;
public Child() {
super();
}
// only called from parent constructor
public void call() {
System.out.println("Child, c is " + (c == null ? "null" : "this"));
}
}
public static void main(String[] args) {
new Child();
}
}
在Java 7之前,这是可能的。 我可以得到这样的特技:
public static class Child extends Parent {
private Child c;
private Child(Object unused) {
super();
}
public Child() {
this(c = this);
}
// only called from parent constructor
public void call() {
System.out.println("Child, c is " + (c == null ? "null" : "this"));
}
}
现在,这将不再适用。 我很欣赏额外的安全性,但是超级电话会破坏它所带来的任何安全性并降低灵活性。
我想要一种规避这种限制的方法。 作为替代方案,我想知道什么是通过限制来获得超级构造函数的情况。
将在超类构造函数之前调用静态初始值设定项。 但是,您将无法设置任何非静态字段,因此很可能无济于事。
http://docs.oracle.com/javase/tutorial/java/javaOO/initial.html
非超级构造函数完成后调用非静态初始化块也没有帮助。
另一种方法可能是在从超级构造函数调用时不执行任何操作,并再次调用子构造函数,例如:
public Child() {
super();
call();
}
public void call() {
if (c==null) {
return;
}
System.out.println("do something with c now");
}
如果在依赖于此方法的超级构造函数中发生更多内容,这将不起作用。
我不得不同意EJP的观点,这是一个坏主意; 找到一个完全不同的解决方案,不涉及折磨构造函数会好得多。
请注意,Java编译器将您的类Child
转换为以下等效项:
public static class Child extends Parent {
private Child c;
public Child() {
super();
c = this;
}
// Remaining implementation
}
对于Java 6和7,这是相同的,当使用任何两个版本进行编译时,构造函数的生成字节代码甚至是相同的。 在调用超级构造函数之后,始终会实例化本地字段。 您使用什么编译器来使您的“解决方案”工作?
这种限制是非常基本的。 这样,您可以依赖首先应用的超级构造函数。 想象一下,你的子构造函数正在使用在这个类中声明的final
字段。 如果您不保证此构造函数执行顺序,则无法保证此字段已初始化。 这种限制使Java更可靠。
这是对“我想知道通过超级构造函数案例的限制所获得的内容”的答案。 部分问题。
在构造过程中,有三种状态,在类X中声明的字段可能在:所有默认值,全部初始化为一致的工作值,以及其他任何内容。
目标似乎是除了X之外的类中的代码只能看到前两个状态中的一个。 当任何X超类的非静态初始化程序或构造函数代码正在运行时,X的字段都处于默认状态。 当X的任何子类的非静态初始化程序或构造函数代码正在运行时,所有X的字段都已初始化为完全一致的可用状态。
只有X初始化程序和构造函数代码必须处理处于不一致状态的X字段,一些是初始化的,一些是默认的,一些是部分初始化的。
通过从X超类初始化器或构造函数调用X方法可以避免这种情况,但这通常被视为反模式。 问题是运行的X代码不是从部分构造的X中的初始化程序或构造函数本地调用的。如果该代码更改字段,则在X初始化程序和构造函数体运行时可能会覆盖此更改。
这应该永远不会起作用。
请注意,在字节码级别,实际上允许这样做。 在字节码中,您可以在调用超类构造函数之前设置当前类中声明的字段。 但是,Java无法使用此行为。 它仅由Java编译器秘密使用,以初始化为支持内部类而添加的合成字段。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.