是否确定从构造函数中调用抽象方法在Java中? [重复](Is it OK to call ab

2019-07-21 06:48发布

这个问题已经在这里有一个答案:

  • 这有什么错在构造函数中覆盖的方法调用? 7个回答

让我们假设我有一个实现Runnable接口的抽象基类。

public abstract class Base implements Runnable {

  protected int param;

  public Base(final int param) {
      System.out.println("Base constructor");
      this.param = param;
      // I'm using this param here
      new Thread(this).start();
      System.out.println("Derivative thread created with param " + param);
  }

  @Override
  abstract public void run();
}

这里是一些衍生类之一。

public class Derivative extends Base {

  public Derivative(final int param) {
      super(param);
  }

  @Override
  public void run() {
      System.out.println("Derivative is running with param " + param);
  }

  public static void main(String[] args) {
      Derivative thread = new Derivative(1);
  }

}

问题的关键是,我想我的基类做的,而不是每一次复制它的一些东西一般。 其实,这是运行良好,输出始终是相同的:

与参数1衍生创建的基本构造函数微分线程与参数1运行

但是,它的安全在Java中启动一个线程调用构造函数中的抽象方法? 因为,在C ++和C#这是在大多数情况下是不安全的,所以据我所知。 谢谢!

Answer 1:

此代码演示了为什么你应该调用一个抽象方法,或任何其他重写方法,从构造函数:

abstract class Super {
    Super() {
        doSubStuff();
    }
    abstract void doSubStuff();
}

class Sub extends Super {
    String s = "Hello world";

    void doSubStuff() {
        System.out.println(s);
    }
}

public static void main(String[] args) {
    new Sub();
}

在运行时,这个打印null 。 这意味着只有“安全”的方法,在一个构造函数是私有的和/或最终的。

在另一方面,你的代码实际上并不叫从构造函数的抽象方法。 相反,你传递一个初始化的对象到另一个线程处理,这更糟糕的是,因为你启动线程,可给予优先考虑和你的前执行Base完成初始化。



Answer 2:

不运行时,因为一个好主意()被调用,衍生对象可能没有被初始化。 如果run()依赖于衍生任何状态下,它可能会失败。

在您简单的情况下,它的工作原理。 但后来有没有点的子类。 你可以简单地

public Base(final int param, Runnable action) {

  new Thread(action).start();


Answer 3:

这是一个非常不好的做法来调用构造函数的抽象方法。 方法从构造方法调用,应始终是私人或决赛中,以防止覆盖。

请参阅此链接到一个问题在这里



Answer 4:

通过this出的构造被称为“让this逃离的构造”,并可能导致一些特别恶劣和莫名其妙的错误,因为对象可能是不一致的状态。

这是特别的情况下,当this被传递到另一个线程,如在这个例子。 由于一个线程中重新排序报表中的JVM中的权利,你可以得到未定义的行为/状态下产生的。



文章来源: Is it OK to call abstract method from constructor in Java? [duplicate]