2011-12-23 11 views
6

新しいスレッドを作成するときに、我々はRunnableをターゲットを供給した場合、そのスレッドの.start()が実行可能な供給のrun()方法を実行することをJava docs状態。java.lang.Threadは、起動時に明示的なjava.lang.Runnableのrun()メソッドを呼び出さないのはなぜですか?

この場合、このテストコードでは "b"を印刷するのではなく "a"が印刷されるべきですか?

public class test { 
    public static void main(String[] args) { 
     Runnable r = new Runnable() { 
      @Override 
      public void run() { 
       System.out.println("a"); 
      } 
     }; 
     Thread t = new Thread(r) { 
      @Override 
      public void run() { 
       System.out.println("b"); 
      } 
     }; 
     t.start(); 
    } 
} 

答えて

16

Thread.run()メソッドをオーバーライドしているためです。ここで

Thread.run()の実装です:

@Override 
public void run() { 
    if (target != null) { 
     target.run(); 
    } 
} 

は、try:

}) { 
    @Override 
    public void run() { 
     super.run(); // ADD THIS LINE 
     System.out.println("b"); 
    } 
}.start(); 

あなたはabを取得します。

+1

これはドキュメントのフレーズエラーではありませんか? Javaドキュメントのhttp://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#Thread%28java.lang.Runnable%29では、作成時にRunnableターゲットを指定した場合、新しいスレッド、そのスレッドの.start()は、(スレッドのrun()メソッドをオーバーライドしているかどうかにかかわらず)指定された実行可能ファイルのrun()メソッドを実行します。それは私がしたことですが、その行動は「定義された」ものではありません。 – Pacerier

+0

まあ厳密に言うと、Thread.run()メソッドが提供するものであり、オーバーライドされた可能性のある機能ではないので、ドキュメントは明確です。 – user802421

+1

他の方法と同様です。メソッドがfinal宣言されていない場合は、契約をオーバーライドして中断することができます。 – user802421

1

実際にはThreadクラスを拡張し、その匿名サブクラスのインスタンスでstartを呼び出しています。

"Java Doc"はjava.lang.Threadクラスのクラスで、そのクラスを拡張するクラスではないという混乱があると思います。

Runnable r = new Runnable() { 
    @Override 
    public void run() { 
     System.out.println("a"); 
    } 
}; 
Thread t = new Thread(r); 

ここで、runを呼び出さないと、java docが間違っています。それは真実ではありません。

+0

はい、それは私がやっていることです。 – Pacerier

+0

@Pacerier:更新を参照してください。 –

9

デフォルトの実装では、Runnableを呼び出します。ただし、デフォルトの実装をオーバーライドしており、実行可能ファイルを呼び出すことはありません。この問題を解決する最も簡単な方法は、

new Thread(new Runnable() { 
     @Override 
     public void run() { 
      System.out.println("a"); 
     } 
    }) { 
     @Override 
     public void run() { 
      super.run(); // call the default implementation. 
      System.out.println("b"); 
     } 
    }.start(); 
+0

http://docs.oracle.com/javase/7/docs/api/java/lang/Thread.html#Thread%28java.lang.Runnable%29は、 "target - このスレッドが実行されるときに実行メソッドが呼び出されるオブジェクト開始されます。あなたはドキュメントが辛口に表現されているとは思わない? – Pacerier

+0

文書は正しいです。別の振る舞いをするサブクラスでクラスをオーバーライドしました。あなたは 'スレッド 'の振る舞いを変更していません。 –

+3

@Pacerier - それは飲み物のガラスを壊して、それがもう水を保持していないことをメーカーに訴えるようなものです。 – Perception

1

であるあなたは、javadocはもはや適用されないと言う何それゆえ、私は匿名のサブクラスであると思うものの中にThread.run()のデフォルトの実装をオーバーライドしています。

あなたは

public class Test { 
public static void main(String[] args) { 

    new Thread(new Runnable() { 
     @Override 
     public void run() { 
      System.out.println("a"); 
     } 
    }) .start(); 
} 
} 

をしようとあなたが期待する答えを得る、a

+0

JavaDocは、何も変更していないかどうかにかかわらず、JavaDocが何を言っているのではないでしょうか? (ドキュメントには、 "デフォルトの実装はこれとこれをオーバーライドするかどうか等など" – Pacerier

+1

が明示されていないので、オーバーライドされたメソッドを新しい実装に置き換えます。 (Runnable'sを使う代わりに)Threadクラスを拡張するときなど、クラスに新しい振る舞いを加えることを可能にする強力な方法です。何が起こると思いますか、オーバーライドとは何と思いましたか? – chrisbunney

1

Runnableの最初のブロックはrunです。 2番目のブロックはrunThreadに上書きします。 Threadstartを呼び出すと、そのrunメソッドが呼び出されます。 ThreadのデフォルトのrunメソッドはRunnable.runメソッドを呼び出しますが、Thread.runをオーバーライドしたため、Runnableを開始するコードはありません。コードは 'b'を出力するだけです。

3

Thread.run()のデフォルトの実装では、javadocをは、

public void run() { 
    if (target != null) { 
     target.run(); 
    } 
} 

しかし、Thread.run()はパブリックである(ソースコードを見て)言うことを行い、それが呼び出すので、あなたは、それを上書きしあなたのprintln( "b")を返し、コンストラクタで渡されたRunnableを完全に無視します。間違いなく、糸。run()はfinalであるべきですが、そうではありません。

1

が持っているドキュメントは、この意見: は「このスレッドが実行を開始させます。Java仮想マシンがこのスレッドのrunメソッドを呼び出し。」ということがべき印刷bの代わりに意味 run()メソッドをThreadに上書きしているため、aです。

1

あなたはstart()メソッドを呼び出しています。あなたが提供したリンクのドキュメントを読むと、次のように表示されます。

public void start() このスレッドは実行を開始します。 Java 仮想マシンがこのスレッドのrunメソッドを呼び出します。

Runnableオブジェクトのrunメソッドを呼び出す場合は、run()メソッドを呼び出す必要があります。

public void run()このスレッドが別の 実行可能オブジェクトを使用して構築された場合、そのRunnableオブジェクトのrunメソッドが呼び出されます。 それ以外の場合、このメソッドは何もせずに戻ります。

関連する問題