是否可以在构造函数中的super()之前进行计算?

Ste*_*gle 65 java

鉴于我有一个类Base,它有一个带有TextBox对象的参数构造函数作为它的参数.如果我有一个简单的以下形式的类:

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?
  }
}
Run Code Online (Sandbox Code Playgroud)

我会收到一个错误,告诉我对super的调用必须是构造函数中的第一个调用.但奇怪的是,我能做到这一点.

public class Simple extends Base {
  public Simple(){
    super(new TextBox());
  }
}
Run Code Online (Sandbox Code Playgroud)

为什么这是有限的,但第一个例子不是?我可以理解需要首先设置子类,也许不允许在调用超级构造函数之前实例化对象变量.但是t显然是一个方法(局部)变量,为什么不允许呢?

有没有办法解决这个限制?有没有一种安全的方法可以将变量保存到您可能构造的内容之前调用super但是在您输入构造函数之后?或者,更一般地说,允许在实际调用super之前进行计算,但是在构造函数中?

谢谢.

wax*_*ing 74

是的,您的简单案例有一个解决方法.您可以创建一个私有构造函数,该构造函数TextBox作为参数并从您的公共构造函数中调用它.

public class Simple extends Base {
    private Simple(TextBox t) {
        super(t);
        // continue doing stuff with t here
    }

    public Simple() {
        this(new TextBox());
    }
}
Run Code Online (Sandbox Code Playgroud)

对于更复杂的东西,您需要使用工厂或静态工厂方法.

  • 这是一个非常方便的模式,几乎可以让你完全规避`super()`在构造函数中没有出现的要求.在极端情况下,您甚至可以将多个私有构造函数链接在一起,但我无法想到我需要这样做的任何情况,如果我这样做,我可能会开始怀疑是否有更好的方法来完成我的工作正在做. (3认同)

小智 24

在超级调用之前,我遇到了相同的计算问题.有时你想在打电话之前检查一些条件super().例如,您有一个在创建时使用大量资源的类.子类需要一些额外的数据,并且可能希望在调用超级构造函数之前先检查它们.有一个简单的方法来解决这个问题.可能看起来有点奇怪,但效果很好:

在类中使用一个私有静态方法,它返回超级构造函数的参数并在里面进行检查:

public class Simple extends Base {
  public Simple(){
    super(createTextBox());
  }

  private static TextBox createTextBox() {
    TextBox t = new TextBox();
    t.doSomething();
    // ... or more
    return t;
  }
}
Run Code Online (Sandbox Code Playgroud)


tra*_*god 8

语言需要它以确保首先可靠地构造超类.特别是,"如果构造函数没有显式调用超类构造函数,Java编译器会自动插入对超类的无参数构造函数的调用."

在您的示例中,超类可能依赖t于构造时的状态.您可以随时要求提供副本.

这里这里有广泛的讨论.

  • 有趣的是,听起来像Java一直在阻止一个最重要的情况,即围绕超类构造函数调用包装代码是有用的:确保如果构造函数抛出异常,事情就可以得到清理.例如,如果某个对象的构造函数重载之一从传入的文件中读取数据,则派生类构造函数可能希望具有接受文件名的重载,将超类构造函数传递给新打开的文件,然后关闭该文件之后.如果超类构造函数抛出,文件如何关闭? (2认同)