3

更新:これは多かれ少なかれ重複であり、 build2でローカル変数を渡すためのコンストラクターを追加するコンパイラーマジックであることが判明しました。

そのようなインターフェースを考えると:

public interface IFoo { public int get(); }

以下のコードは、build2によって返された値に対してgetClass()。newInstance()を呼び出そうとすると、1、1、2を出力し、例外をスローしますが、build1の戻り値に対して同じものを呼び出そうとすると例外をスローします。なぜ何かアイデアはありますか?

public class Foo {

 public static IFoo build1() {
  return new IFoo() { public int get() { return 1; } };
 }

 public static IFoo build2(final int v) {
  return new IFoo() { public int get() {return v;} };
 }

 public static void main(String[] args) throws Exception {
  IFoo foo, bar;

  foo = build1();
  System.out.println(foo.get());

  bar = foo.getClass().newInstance();  
  System.out.println(bar.get());

  foo = build2(2);
  System.out.println(foo.get());

  bar = foo.getClass().newInstance();  
  System.out.println(bar.get());
 }
}

私のデバッガーは、newInstance()呼び出しで、getConstructor0がNoSuchMethodExceptionをスローしていることを示しています。

4

1 に答える 1

4

何が起こるかです:

  • newInstance()nullaryコンストラクタが必要です
  • 変数にアクセスする匿名クラスを作成すると、finalこの値を保持するフィールドが実際に暗黙的に作成され、最初は暗黙のコンストラクターに渡されます。
  • したがって、でIFoo作成されたものにbuild2は実際にはnullaryコンストラクターがありません

何が起こっているかを示すスニペットを次に示します。

import java.lang.reflect.*;
public class Foo {
    interface IFoo { public int get(); }

    public static IFoo build2(final int v) {
        return new IFoo() { public int get() {return v;} };
    }
    public static void main(String[] args) throws Exception {
        Class<?> klazz = build2(42).getClass();
        for (Constructor<?> c : klazz.getDeclaredConstructors()) {
            System.out.println(c);
        }
        // prints: Foo$1(int)
    }
}

(匿名クラスFoo$1に割り当てられたバイナリ名)にはコンストラクタが1つしかないことを示しており、。が必要です。返されるのは、この暗黙的に作成されたコンストラクターによって暗黙的に作成されたフィールドに割り当てられたものであるため、これが可能な方法です。IFoointreturn v

Foo$1(egを使用して)逆コンパイルして、javap -cどのバイトコードが生成されるかを確認することは有益です。final実際、これは、変数が匿名クラスによってアクセスされたときに発生することであることがわかります。

関連する質問

于 2010-08-10T19:11:19.497 に答える