このサンプルコードを考えると:
Runnable r = new Runnable() {
public void run() {
System.out.print("Cat");
}
};
Thread t = new Thread(r) {
public void run() {
System.out.print("Dog");
}
};
t.start();
なぜ出力はCatではなくDogなのですか?
run
inの実装は、コンストラクターで提供されているものがあれば、それをThread
呼び出すだけです。Runnable
そのコードをオーバーライドしているので、新しいスレッドでrun
メソッドが呼び出されただけの場合、Runnable
は無視されます。もちろん、ソースコードを見てそれを確認できるはずです...(私はちょうどそうしました、そして私はここにソースを投稿するつもりはありませんが、それは私が説明したことを正確に行います。)
あなたが実際に明らかにしたのはカプセル化の問題です-スレッドが何をすThread
べきかを言うこれらの異なる、潜在的に矛盾する方法を持つべきではありません。基本的に、直接拡張することはほとんどありません。Thread
ひどく設計されているからといって、その貧弱なデザインを悪用しなければならないという意味ではありません;)
編集:これは実際には、やや回りくどい方法で文書化されています。start()
次のように文書化されています:
このスレッドに実行を開始させます。Java仮想マシンは、このスレッドのrunメソッドを呼び出します。
そしてrun()
、次のように文書化されています:
このスレッドが別のRunnablerunオブジェクトを使用して構築された場合、そのRunnableオブジェクトのrunメソッドが呼び出されます。それ以外の場合、このメソッドは何もせずに戻ります。
したがって、run()
メソッドはのように呼び出されますが、コンストラクターで提供されたものを呼び出す唯一のメソッドであるをstart()
オーバーライドしました。run()
Runnable
次のようにメソッドをオーバーライドした場合は、次の点に注意してください。
Thread t = new Thread(r) {
public void run() {
super.run();
System.out.print("Dog");
}
};
その場合、出力は「CatDog」になります。
Thread.run
ランナブルを実行しないようにオーバーライドしました。代わりに、単に「Dog」と出力します。
関数run()
がオーバーライドされているためです。そしてt
、この関数を呼び出します。
public void run() {
System.out.print("Dog");
}
関数を呼び出すcat
実行時と同じようにo/pを取得しますr.start()
public void run() {
System.out.print("Cat");
}
のソースコードを見てみましょうjava.lang.Thread
:
public void run() {
if (target != null) {
target.run();
}
}
target
コンストラクターが変数を割り当てるために使用するフィールドRunnable
ですThread
。のメソッドをオーバーライドすると、を呼び出す動作が変更されます。Thread(Runnable)
r
run
Thread
run
System.out.print("Dog");
電話する代わりに
if (target != null) {
target.run();
}
これは匿名クラスであり、を再定義/オーバーライドしていますrun
。あなたはあなたの中で渡されたものを使用してRunnable
いますrun
か?いいえ、しません。だから問題は、なぜそれが印刷されると思ったのCat
ですか?
new Thread(r) {
public void run() {
System.out.print("Dog");
}
};