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

℡╲_俬逩灬. 提交于 2019-11-26 09:11:00

问题


This question already has an answer here:

  • What's wrong with overridable method calls in constructors? 7 answers

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

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 constructor Derivative thread created with param 1 Derivative is running with param 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!


回答1:


This code demonstrates why you should never call 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.

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 Base finishes its initialization.




回答2:


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.

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



回答3:


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




回答4:


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

This is especially the case when this is 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.



来源:https://stackoverflow.com/questions/15327417/is-it-ok-to-call-abstract-method-from-constructor-in-java

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!