Java 是否可以在构造函数中的 super() 之前进行计算?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/2303604/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Is it possible to do computation before super() in the constructor?
提问by Stephen Cagle
Given that I have a class Base that has a single argument constructor with a TextBox object as it's argument. If I have a class Simple of the following form:
鉴于我有一个 Base 类,它有一个带有 TextBox 对象作为参数的单参数构造函数。如果我有以下形式的 Simple 类:
public class Simple extends Base {
public Simple(){
TextBox t = new TextBox();
super(t);
//wouldn't it be nice if I could do things with t down here?
}
}
I will get a error telling me that the call to super must be the first call in a constructor. However, oddly enough, I can do this.
我会收到一个错误,告诉我对 super 的调用必须是构造函数中的第一个调用。然而,奇怪的是,我可以做到这一点。
public class Simple extends Base {
public Simple(){
super(new TextBox());
}
}
Why is it that this is permited, but the first example is not? I can understand needing to setup the subclass first, and perhaps not allowing object variables to be instantiated before the super-constructor is called. But t is clearly a method (local) variable, so why not allow it?
为什么这是允许的,而第一个示例则不允许?我可以理解需要首先设置子类,并且可能不允许在调用超级构造函数之前实例化对象变量。但是 t 显然是一个方法(局部)变量,为什么不允许呢?
Is there a way to get around this limitation? Is there a good and safe way to hold variables to things you might construct BEFORE calling super but AFTER you have entered the constructor? Or, more generically, allowing for computation to be done before super is actually called, but within the constructor?
有没有办法绕过这个限制?有没有一种好的和安全的方法来保存你在调用 super 之前但在你进入构造函数之后可能构造的东西的变量?或者,更一般地说,允许在实际调用 super 之前完成计算,但在构造函数中?
Thank you.
谢谢你。
采纳答案by waxwing
Yes, there is a workaround for your simple case. You can create a private constructor that takes TextBox
as an argument and call that from your public constructor.
是的,对于您的简单案例,有一种解决方法。您可以创建一个私有构造函数,将其TextBox
作为参数并从您的公共构造函数中调用它。
public class Simple extends Base {
private Simple(TextBox t) {
super(t);
// continue doing stuff with t here
}
public Simple() {
this(new TextBox());
}
}
For more complicated stuff, you need to use a factory or a static factory method.
对于更复杂的东西,您需要使用工厂或静态工厂方法。
回答by CodingInsomnia
The reason why the second example is allowed but not the first is most likely to keep the language tidy and not introduce strange rules.
之所以允许第二个示例而不是第一个示例,很可能是为了保持语言整洁,并且不会引入奇怪的规则。
Allowing any code to run before super has been called would be dangerous since you might mess with things that should have been initialized but still haven't been. Basically, I guess you can do quite a lot of things in the call to super itself (e.g. call a static method for calculating some stuff that needs to go to the constructor), but you'll never be able to use anything from the not-yet-completely-constructed object which is a good thing.
允许在调用 super 之前运行任何代码是危险的,因为您可能会弄乱本应已初始化但仍未初始化的内容。基本上,我想你可以在调用 super 本身时做很多事情(例如调用一个静态方法来计算一些需要转到构造函数的东西),但是你永远不能使用 not -尚未完全构建的对象,这是一件好事。
回答by trashgod
It is requiredby the language in order to ensure that the superclass is reliably constructed first. In particular, "If a constructor does not explicitly invoke a superclass constructor, the Java compiler automatically inserts a call to the no-argument constructor of the superclass."
语言需要它以确保首先可靠地构造超类。特别是,“如果构造函数没有显式调用超类构造函数,Java 编译器会自动插入对超类的无参数构造函数的调用。”
In your example, the superclass may rely on the state of t
at construction time. You can always ask for a copy later.
在您的示例中,超类可能依赖t
于构造时的状态。您以后可以随时索要副本。
回答by David Nouls
That's how Java works :-) There are technical reasons why it was chosen this way. It might indeed be odd that you can not do computations on locals before calling super, but in Java the object must first be allocated and thus it needs to go all the way up to Object so that all fields are correctly initialized before your could accidently moddify them.
这就是 Java 的工作方式 :-) 选择这种方式是有技术原因的。在调用 super 之前不能对 locals 进行计算确实可能很奇怪,但是在 Java 中,必须首先分配对象,因此它需要一直到 Object 以便在您意外修改之前正确初始化所有字段他们。
In your case there is most of the time a getter that allows you to access the parameter your gave to super(). So you would use this:
在您的情况下,大多数情况下都有一个 getter 允许您访问您提供给 super() 的参数。所以你会使用这个:
super( new TextBox() ); final TextBox box = getWidget(); ... do your thing...
回答by Ben
I had the same problem with computation before super call. Sometimes you want to check some conditions before calling super()
. For example, you have a class that uses a lot of resources when created. the sub-class wants some extra data and might want to check them first, before calling the super-constructor. There is a simple way around this problem. might look a bit strange, but it works well:
在超级调用之前,我在计算方面遇到了同样的问题。有时您想在调用之前检查一些条件super()
。例如,您有一个在创建时使用大量资源的类。子类需要一些额外的数据,并且可能希望在调用超级构造函数之前先检查它们。有一个简单的方法可以解决这个问题。可能看起来有点奇怪,但效果很好:
Use a private static method inside your class that returns the argument of the super-constructor and make your checks inside:
在您的类中使用私有静态方法,该方法返回超级构造函数的参数并在内部进行检查:
public class Simple extends Base {
public Simple(){
super(createTextBox());
}
private static TextBox createTextBox() {
TextBox t = new TextBox();
t.doSomething();
// ... or more
return t;
}
}
回答by loweryjk
You can define a static supplier lambda which can contain more complicated logic.
您可以定义一个静态供应商 lambda,它可以包含更复杂的逻辑。
public class MyClass {
private static Supplier<MyType> myTypeSupplier = () -> {
return new MyType();
};
public MyClass() {
super(clientConfig, myTypeSupplier.get());
}
}