2

最後のコードはコンパイルエラーを生成します:

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) {
    }
}
4

3 に答える 3

16

コードサンプルの動作の説明は、this現在「最も」内部にいるクラスとして定義されていることです。この場合、実行可能をサブクラス化する匿名内部クラス内で「ほとんど」であり、に一致するメソッドはありませんrun(int)。検索範囲を広げるには、を指定しthisて使用するものを指定しますNotApplicable.this.run(42)

jvmは次のように評価します。

thisRunnable->現在実行中のwithメソッドのインスタンスrun()

NotApplicable.thisNotApplicable->現在実行中のwithメソッドのインスタンスrun(int)

コンパイラーは、メソッドの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" );
    }
}
于 2008-10-31T01:54:31.793 に答える
1

私が覚えている限りでは、ネストされたクラス間で実行するメソッドを選択するための規則は、継承ツリーでメソッドを選択するための規則とほぼ同じです。つまり、ここで取得しているのは過負荷ではなく、隠れているということです。これらの違いは、継承のメソッドを理解する上で非常に重要です。

Runnable がサブクラスとして宣言されている場合、run() メソッドは親の run(int) メソッドを非表示にします。run(...) への呼び出しは、Runnable で実行しようとしますが、署名と一致しない場合は失敗します。foo は子で宣言されていないため、親のものが呼び出されます。

ここでも同じ原理が起こっています。「メソッドの隠蔽」への参照を調べてください。明確なはずです。

于 2008-10-31T15:27:22.770 に答える
0

これは、スコープrunに入るときに再宣言されているためです。new Runnable() {}実行する以前のすべてのバインディングにアクセスできなくなります。それはあなたがこれをしているようです:

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ん。最初の参照を見つけて、タイプに互換性がないことを確認すると、コンパイラは停止します。

注:これができなかったわけではありません...それは、あなた自身の正気を保つために、そうすべきではないと決定されたということです。

于 2008-10-31T00:51:04.743 に答える