为什么这个()和超级()必须是构造函数中的第一个语句?

为什么这个()和超级()必须是构造函数中的第一个语句?

Java要求,如果在构造函数中调用了这个()或超级(),那么它必须是第一个语句。为什么?

例如:

public class MyClass {
    public MyClass(int x) {}}public class MySubClass extends MyClass {
    public MySubClass(int a, int b) {
        int c = a + b;
        super(c);  // COMPILE ERROR
    }}

Sun编译器说:“调用超级必须是构造函数中的第一条语句”。Eclipse编译器说“构造器调用必须是构造函数中的第一个语句”。

但是,您可以通过稍微重新排列代码来解决这个问题:

public class MySubClass extends MyClass {
    public MySubClass(int a, int b) {
        super(a + b);  // OK
    }}

下面是另一个例子:

public class MyClass {
    public MyClass(List list) {}}public class MySubClassA extends MyClass {
    public MySubClassA(Object item) {
        // Create a list that contains the item, and pass the list to super
        List list = new ArrayList();
        list.add(item);
        super(list);  // COMPILE ERROR
    }}public class MySubClassB extends MyClass {
    public MySubClassB(Object item) {
        // Create a list that contains the item, and pass the list to super
        super(Arrays.asList(new Object[] { item }));  // OK
    }}

所以,它是不阻止您执行逻辑在打电话给超级英雄之前。它只是阻止您执行逻辑,您不能适应一个单一的表达式。

对于调用,也有类似的规则。this()..编译器说“调用这必须是构造函数中的第一个语句”。

为什么编译器有这些限制?您能给出一个代码示例,如果编译器没有这个限制,那么会发生一些不好的事情吗?


狐的传说
浏览 496回答 3
3回答

RISEBY

通过链接构造函数和静态方法,我找到了解决这一问题的方法。我想做的事情看起来是这样的:public class Foo extends Baz {   private final Bar myBar;   public Foo(String arg1, String arg2) {     // ...     // ... Some other stuff needed to construct a 'Bar'...     // ...     final Bar b = new Bar(arg1, arg2);     super(b.baz()):     myBar = b;   }}因此,基本上是基于构造函数参数构造一个对象,将对象存储在一个成员中,并将该对象上的一个方法的结果传递给超级构造函数。使成员成为最终成员也是相当重要的,因为类的本质是它是不可变的。注意,实际上构建Bar需要几个中间对象,所以在我的实际用例中,它是不可还原为一行的。最后我做了这样的事情:public class Foo extends Baz {   private final Bar myBar;   private static Bar makeBar(String arg1,  String arg2) {     // My more complicated setup routine to actually make 'Bar' goes here...     return new Bar(arg1, arg2);   }   public Foo(String arg1, String arg2) {     this(makeBar(arg1, arg2));   }   private Foo(Bar bar) {     super(bar.baz());     myBar = bar;   }}它完成了在调用超级构造函数之前执行多个语句的任务。

慕村225694

因为JLS这么说。是否可以兼容的方式更改JLS以使其允许? 是啊。然而,这将使语言规范复杂化,因为语言规范已经足够复杂了。这不是一件非常有用的事情,而且有一些方法可以绕过它(用静态方法或lambda表达式的结果调用另一个构造函数)this(fn())-方法是在其他构造函数之前调用的,因此也是超级构造函数)。因此,做这种改变的权力与重量之比是不利的。请注意,仅此规则并不阻止在超类完成构造之前使用字段。考虑一下这些非法的例子。super(this.x = 5);super(this.fn());super(fn());super(x);super(this instanceof SubClass);// this.getClass() would be /really/ useful sometimes.这个例子是合法的,但“错了”。class MyBase {     MyBase() {         fn();     }     abstract void fn();}class MyDerived extends MyBase {     void fn() {        // ???     }}在上面的示例中,如果MyDerived.fn所需的参数MyDerived构造函数,它们需要使用ThreadLocal. ;(顺便说一句,自Java1.4以来,包含外部的合成字段this在调用内部类超级构造函数之前分配。这引起了NullPointerException编译为针对早期版本的代码中的事件。还请注意,在不安全发布的情况下,除非采取了预防措施,否则其他线程可以重新查看构造。2018年3月编辑:在讯息中记录:建造和验证Oracle建议取消这一限制(但与C#不同的是,this将是绝对没有分配(Du)构造函数链接之前)。在历史上,这个()或超级()必须是构造函数中的第一个。这种限制从来不受欢迎,被认为是武断的。有一些微妙的原因,包括特别是对请求的核查,促成了这一限制。多年来,我们已经在VM级别解决了这些问题,以至于考虑取消这个限制变得非常实际,不仅对记录,而且对所有构造函数都是如此。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java