web-dev-qa-db-ja.com

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

そして、これは数少ない派生クラスの1つです。

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

}

重要なのは、Baseクラスに毎回コピーするのではなく、一般的なことを実行してもらいたいということです。実際には、正常に動作しており、出力は常に同じです。

基本コンストラクターparam1で作成された派生スレッドDerivativeはparam1で実行されています

しかし、コンストラクターで抽象メソッドを呼び出すスレッドを開始するのは安全ですIN Java?なぜなら、C++とC#では、私が知る限り、ほとんどの場合安全ではないからです。ありがとうございます。

21
Danylo Fitel

このコードは、コンストラクターから抽象メソッドまたはその他のオーバーライド可能なメソッドを決して呼び出さない理由を示しています。

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が初期化を完了する前に実行される可能性があるためです。

31
Ryan Stewart

Run()が呼び出されたときに、Derivativeオブジェクトが初期化されていない可能性があるため、お勧めできません。 run()がDerivativeの状態に依存している場合、失敗する可能性があります。

あなたの単純なケースでは、それは機能します。しかし、サブクラスには意味がありません。あなたは簡単にできます

public Base(final int param, Runnable action) {

  new Thread(action).start();
3
irreputable

コンストラクターから抽象メソッドを呼び出すことは非常に悪い習慣です。コンストラクターから呼び出されるメソッドは、オーバーライドを防ぐために、常にプライベートまたはファイナルである必要があります。

質問へのこのリンクを参照してください ここ

2
Igor Rodriguez

コンストラクターからthisを渡すことは、「コンストラクターからthisをエスケープする」と呼ばれ、オブジェクトが一貫性のない状態にある可能性があるため、特に厄介で奇妙なバグにつながる可能性があります。

これは、この例のように、thisが別のスレッドに渡される場合に特に当てはまります。スレッド内でステートメントを並べ替えるJVMの権利により、未定義の動作/状態が発生する可能性があります。

1
Bohemian