2

以下のスニペットをテストしています。tx または t.hello にアクセスする方法を知る必要がありますか? その範囲は何ですか?開発者はこのように変数を定義しますか?

public class Test{

public Test(){
    System.out.print("constructor\n");
}

public static void main(String[] args) {

    Test t = new Test(){
        int x = 0;
        //System.out.print("" + x);
        void hello(){
            System.out.print("inside hello\n");
        }
    };
}

編集

しかし、なぜこのスニペットが機能したのか

 Thread  tr = new Thread() {
int loops = 1;

 @Override
 public void run() {
    loops += 1;
}
};
tr.start();
4

4 に答える 4

3

宣言と定義を区別する必要があります。

あなたの場合、クラスの変数を宣言し、それをいくつかの追加要素を持つクラス(匿名クラス)Testから派生したクラスのオブジェクトに割り当てます。Test

この定義の後のコードはtof クラスのみを認識し、 and を持っていないためTest何も知りません。xhelloTest

したがって、リフレクションとは別に、無名クラスの定義後にxandを使用することはできません。helloはい、開発者は、定義内でこれらの変数が必要な場合に、そのような変数を使用します。

Testメソッドを呼び出して、定義直後の一部ではない変数にアクセスできることが言及されました。

int y = new Test(){
    int x = 0;
    //System.out.print("" + x);
    void hello(){
        System.out.print("inside hello\n");
    }
}.x;

これができるのは、この時点でオブジェクトの型がわかっているからです (これは匿名クラスです)。このオブジェクトを に割り当てるとすぐにTest t、この情報は失われます。

于 2013-01-06T20:36:14.677 に答える
1

匿名の内部クラスを作成します。この場合、ほとんど使用されません。匿名クラスは通常、まったく新しいクラスを作成せずにインターフェイスを実装するために使用されます。これを行うと、必要な数のメンバーを追加できます。例えば:

Runnable r = new Runnable() {
    int i = 0;
    public void run() {
        System.out.println(i++);
    }
};

そうすることで、Runnableインターフェース(そのようなフィールドを持たない)の実装にカウンターを追加し、呼び出すたびr.run();に増分値が出力されます。

同様のパターンを使用するあまり工夫されていない例:

private final ExecutorService executor = Executors.newCachedThreadPool(new ThreadFactory() {
    private final AtomicInteger threadId = new AtomicInteger();

    @Override
    public Thread newThread(Runnable r) {
        return new Thread(r, "Thread #" + threadId.incrementAndGet());
    }
});

ここでは、新しい各スレッドに名前を付けるThreadFactoryの基本的な実装が提供されていますThread #i

于 2013-01-06T20:32:16.240 に答える
1

あなたのコードは、匿名の内部クラスを作成します。これは(多かれ少なかれ)これを行うことと同等です:

public class Test {
    // ...
    private class TestAnonymousInner extends Test {
        int x = 0;
        //System.out.print("" + x);
        void hello(){
            System.out.print("inside hello\n");
        }
    }

    public static void main(String[] args) {
        Test t = new TestAnonymousInner();
        // invalid:
        // t.hello(); 
    }
}

そのファイルのコンパイラ出力を見ると、次のような名前のファイルがあることに気付くでしょうTest$1.class。これは、定義した無名クラスです。

インスタンスを格納している変数は typeTestであるため、それを介してフィールドにアクセスすることはできません。リフレクションまたはコンストラクタ式からアクセスできます。たとえば、特に有用ではありませんが、次のように動作します。

new Test() {
    void hello() {
        System.out.println("hello()");
    }
}.hello(); // should print "hello()"

Re: あなたの編集。start()の方法ですThread。変数trの型も であるThreadため、そのメソッドを呼び出すことができます。AICに追加するメソッドではありません。

于 2013-01-06T20:16:50.790 に答える
1

書いてある通り、t が参照するオブジェクトの外では x も hello もアクセスできません。問題は、それらが t の匿名クラスでのみ宣言されていることです。これらは Test で定義されておらず、匿名であるため、宣言されている型に t 参照をキャストすることはできません。

Test を抽象化し、hello の抽象宣言を追加して、t によって参照されるオブジェクトの外部から呼び出すことができるように Test を変更しました。また、x の使用を追加するために hello を変更しました。これらの変更は、匿名クラスの機能にアクセスする 2 つの方法 (基底クラスを使用する方法と内部的に使用する方法) を示しています。

public abstract class Test {

  abstract void hello();

  public Test() {
    System.out.print("constructor\n");
  }

  public static void main(String[] args) {

    Test t = new Test() {
      int x = 0;

      // System.out.print("" + x);
      void hello() {
        System.out.print("inside hello\n");
        System.out.print("My value of x is "+x);
      }
    };
    t.hello();

  }
}
于 2013-01-06T20:51:32.230 に答える