同じ名前の匿名クラスの外部でメソッドを呼び出せないのはなぜですか
-
05-07-2019 - |
質問
最後のコードはコンパイルエラーを生成します:
NotApplicable.java:7: run() in cannot be applied to (int)
run(42);
^
1 error
問題はなぜですか? javacがrun()を呼び出していると判断し、run(int bar)が見つからないのはなぜですか? foo(int bar)を正しく呼び出しました。 NotApplicable.this.run(42);を使用する必要があるのはなぜですか?バグですか?
public class NotApplicable {
public NotApplicable() {
new Runnable() {
public void run() {
foo(42);
run(42);
// uncomment below to fix
//NotApplicable.this.run(42);
}
};
}
private void run(int bar) {
}
public void foo(int bar) {
}
}
解決
コードサンプルの動作の説明は、 this
が現在「最も」のクラスであると定義されていることです。の中に。この場合、あなたは「ほとんど」です。 runnableをサブクラス化する匿名内部クラス内にあり、 run(int)
に一致するメソッドはありません。検索範囲を広げるには、 NotApplicable.this.run(42)
と記述して、使用する this
を指定します。
jvmは次のように評価します:
this
->現在、メソッド run()
Runnable
のインスタンスを実行しています
NotApplicable.this
->現在、メソッド run(int)
NotApplicable
のインスタンスを実行しています
コンパイラは、メソッドのNAMEに一致する最初のメソッドのネストツリーを検索します。 –この説明についてDJClayworthに感謝します
匿名の内部クラスは、外部クラスのサブクラスではありません。この関係により、内側のクラスと外側のクラスの両方がまったく同じシグネチャを持つメソッドを持つことができ、最も内側のコードブロックは実行するメソッドを識別できるはずです。
public class Outer{
public Outer() {
new Runnable() {
public void printit() {
System.out.println( "Anonymous Inner" );
}
public void run() {
printit(); // prints "Anonymous Inner"
this.printit(); //prints "Anonymous Inner"
// would not be possible to execute next line without this behavior
Outer.this.printit(); //prints "Outer"
}
};
}
public void printit() {
System.out.println( "Outer" );
}
}
他のヒント
思い出す限り、ネストされたクラス間で実行するメソッドを選択するためのルールは、継承ツリーでメソッドを選択するためのルールとほぼ同じです。つまり、ここで得ているのは過負荷ではなく、隠れているということです。これらの違いは、継承のメソッドを理解するために重要です。
Runnableがサブクラスとして宣言されている場合、run()メソッドは親のrun(int)メソッドを非表示にします。 run(...)を呼び出すと、Runnableで実行が試行されますが、署名と一致しない場合は失敗します。 fooは子で宣言されていないため、親のfooが呼び出されます。
同じ原理がここで起こっています。 「メソッドの非表示」への参照を検索します。そしてそれは明確でなければなりません。
これは、 new Runnable(){}
スコープに入ると、 run
が再宣言されるためです。実行する以前のすべてのバインディングにアクセスできなくなります。これをやっているように:
import java.util.*;
public class tmp
{
private int x = 20;
public static class Inner
{
private List x = new ArrayList();
public void func()
{
System.out.println(x + 10);
}
}
public static void main(String[] args)
{
(new Inner()).func();
}
}
コンパイラは、スコープスタック全体で x
の型に一致するものを探しません。最初の参照が見つかり、型に互換性がないことがわかると停止します。 。
注:これはできなかったようではありません...それはただ、あなた自身の正気を保つために、すべきではないことが決定されました。