在Java中从构造函数调用抽象方法可以吗?
假设我有一个实现了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(); }
这是几个派生类之一。
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 Derivative创build的衍生线程使用参数1运行
但在JAVA中是否安全启动调用构造函数中抽象方法的线程? 因为在C ++和C#中,大多数情况下是不安全的,据我所知。 谢谢!
这段代码演示了为什么不应该从构造函数中调用抽象方法或其他可重写的方法:
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
完成初始化之前执行。
从构造函数调用抽象方法是一个非常糟糕的做法。 从构造函数调用的方法应始终是私有的或最终的,以防止重写。
在这里看到这个链接到一个问题
从run()被调用时,不是一个好主意,Derivative对象可能没有被初始化。 如果run()取决于Derivative中的任何状态,则可能会失败。
在你的简单情况下,它的作品。 但是这个子类没有意义。 你可以简单
public Base(final int param, Runnable action) { new Thread(action).start();
把this
从构造函数中传递出来叫做“让它从构造函数中转义出来”,并且会导致一些特别讨厌和怪异的错误,因为这个对象可能处于不一致的状态。
这是特别的情况下, this
是传递给另一个线程,如在这个例子中。 由于JVM有权对线程中的语句进行重新sorting,因此可能会发生未定义的行为/状态。