java 在Java中从构造函数调用抽象方法可以吗?

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/15327417/
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

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-31 19:15:43  来源:igfitidea点击:

Is it OK to call abstract method from constructor in Java?

javamethodsconstructorvirtualabstract

提问by Danylo Fitel

Let's suppose I have an abstract Base class that implements Runnable interface.

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

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();
}

And here is one of a few derivative classes.

这是少数派生类之一。

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);
  }

}

The point is that I want my Base class do some general stuff instead of copying it every time. Actually, it's running fine, the output is always the same:

关键是我希望我的 Base 类做一些通用的事情,而不是每次都复制它。实际上,它运行良好,输出始终相同:

Base constructor Derivative thread created with param 1 Derivative is running with param 1

使用参数 1 创建的基本构造函数衍生线程使用参数 1 创建衍生线程

But is it safe IN JAVA to start a thread calling the abstract method in constructor? Because, in C++ and C# it is unsafe in most cases, so far as I know. Thank you!

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

回答by Ryan Stewart

This code demonstrates why you should nevercall an abstract method, or any other overridable method, from a constructor:

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

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();
}

When run, this prints null. This means the only "safe" methods to have in a constructor are private and/or final ones.

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

On the other hand, your code doesn't actually call an abstract method from a constructor. Instead, you pass an uninitialized object to another thread for processing, which is worse, since the thread you're starting may be given priority and execute before your Basefinishes its initialization.

另一方面,您的代码实际上并未从构造函数调用抽象方法。相反,您将一个未初始化的对象传递给另一个线程进行处理,这更糟糕,因为您正在启动的线程可能会获得优先级并在您Base完成初始化之前执行。

回答by irreputable

Not a good idea since when run() is invoked, the Derivative object may not have been initialized. If run() depends on any state in Derivative, it can fail.

这不是一个好主意,因为在调用 run() 时,可能尚未初始化 Derivative 对象。如果 run() 依赖于 Derivative 中的任何状态,则它可能会失败。

In your simple case it works. But then there's no point for the subclass. You can simply

在您的简单情况下,它有效。但是子类就没有意义了。你可以简单地

public Base(final int param, Runnable action) {

  new Thread(action).start();

回答by Igor Rodriguez

It's a very bad practice to call an abstract method from a constructor. Methods called from constructors should always be private or final, to prevent overriding.

从构造函数调用抽象方法是一种非常糟糕的做法。从构造函数调用的方法应该始终是私有的或最终的,以防止覆盖。

See this link to a question here

在此处查看此问题的链接

回答by Bohemian

Passing thisout of the constructor is called "letting thisescape from the constructor", and can lead to some particularly nasty and weird bugs, because the object may be in an inconsistent state.

传递this出构造函数称为“this从构造函数中逃逸”,并且会导致一些特别讨厌和奇怪的错误,因为对象可能处于不一致的状态。

This is especially the case when thisis passed to another thread, as in this example. Due to the JVMs right to reorder statements within a thread, you can get undefined behaviour/state occurring.

this传递给另一个线程时尤其如此,如本例所示。由于 JVM 有权在线程内重新排序语句,您可能会遇到未定义的行为/状态。