2

漠然と言えば、Java では、無名クラスはある種の閉鎖を提供しますfinal。無名クラス内から ( ) 変数にアクセスすることが可能です。以下では、この種の変数を「クロージャー変数」と呼びます。

匿名クラスのコンストラクターのシグネチャは、そのような変数が定数か非定数かによって異なります

非定数の「クロージャー変数」に反射的にアクセスするエレガントな方法はありますか?

この課題を示す私のテスト クラスは次のとおりです。

package com.example;

import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;

import org.junit.Test;

public class ReflectiveInstantiationAnonymousClassTest {

    @Test
    public void testInstantiateConstantAnonymousClassReflectively() {
        System.out
                .println("About to define anonymous class with constant closure");
        final String constantString = "constant String";
        System.out.println("constantString is " + constantString);

        Class<? extends Object> clazz = new Object() {
            public String toString() {
                return "Hello with " + constantString;
            }
        }.getClass();

        Object anonymousClassInstance1 = instantiateAnonymousClass(clazz);
        Object anonymousClassInstance2 = instantiateAnonymousClass(clazz);
        System.out.println(anonymousClassInstance1);
        System.out.println(anonymousClassInstance2);
    }


    @Test
    public void testInstantiateNonConstantAnonymousClassReflectively() {
        System.out
                .println("About to define anonymous class with variable closure");
        final String variableString = String.valueOf( System.currentTimeMillis() );
        System.out.println("variableString is " + variableString);

        Class<? extends Object> clazz = new Object() {
            public String toString() {
                return "Hello with " + variableString;
            }
        }.getClass();

        Object anonymousClassInstance1 = instantiateAnonymousClass(clazz);
        Object anonymousClassInstance2 = instantiateAnonymousClass(clazz);
        System.out.println(anonymousClassInstance1);
        System.out.println(anonymousClassInstance2);
    }

    @SuppressWarnings("unchecked")
    private <T> T instantiateAnonymousClass(Class<T> clazz) {
        T instance = null;
        Constructor<?>[] allConstructors = clazz.getDeclaredConstructors();
        System.out.println("-+-" + allConstructors.length + " constructor(s) defined by class " + clazz.getName() );
        for(Constructor<?> constructor : allConstructors) {
            System.out.println(" +- a constructor  with " + constructor.getParameterTypes().length + " parameter(s): " + constructor.toGenericString() );
        }
        System.out.println();
        System.out.println("Instantiating anonymous class");
        try {
            instance = (T) clazz.getDeclaredConstructors()[0].newInstance(this);
            //                                                                .
            //                                                               /|\
            //    how can I provide a variable closure variable there?--------+

        } catch (InstantiationException | IllegalAccessException
                | IllegalArgumentException | InvocationTargetException
                | SecurityException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }

        return instance;
    }
}

テスト ケースtestInstantiateConstantAnonymousClassReflectivelyは正常に機能し、次のように出力されます。

About to define anonymous class with constant closure
constantString is constant String
-+-1 constructor(s) defined by class com.example.ReflectiveInstantiationAnonymousClassTest$1
 +- a constructor  with 1 parameter(s): com.example.ReflectiveInstantiationAnonymousClassTest$1(com.example.ReflectiveInstantiationAnonymousClassTest)

Instantiating anonymous class
-+-1 constructor(s) defined by class com.example.ReflectiveInstantiationAnonymousClassTest$1
 +- a constructor  with 1 parameter(s): com.example.ReflectiveInstantiationAnonymousClassTest$1(com.example.ReflectiveInstantiationAnonymousClassTest)

Instantiating anonymous class
Hello with constant String
Hello with constant String

ただし、テストケースは次のように出力します。testInstantiateNonConstantAnonymousClassReflectively

About to define anonymous class with variable closure
variableString is 1371946280882
-+-1 constructor(s) defined by class com.example.ReflectiveInstantiationAnonymousClassTest$2
 +- a constructor  with 2 parameter(s): com.example.ReflectiveInstantiationAnonymousClassTest$2(com.example.ReflectiveInstantiationAnonymousClassTest,java.lang.String)

Instantiating anonymous class
java.lang.IllegalArgumentException: wrong number of arguments
    at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
    at sun.reflect.NativeConstructorAccessorImpl.newInstance(NativeConstructorAccessorImpl.java:57)
    at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(DelegatingConstructorAccessorImpl.java:45)
    at java.lang.reflect.Constructor.newInstance(Constructor.java:525)
    at com.example.ReflectiveInstantiationAnonymousClassTest.instantiateAnonymousClass(ReflectiveInstantiationAnonymousClassTest.java:60)
    at com.example.ReflectiveInstantiationAnonymousClassTest.testInstantiateNonConstantAnonymousClassReflectively(ReflectiveInstantiationAnonymousClassTest.java:43)

test caseでは、異なる種類のコンストラクターが生成されることに注意してください。このコンストラクターには追加のパラメーターが必要です。これは、 「焼き付ける」ことができず、実行時にのみ決定できるためです。testInstantiateNonConstantAnonymousClassReflectivelyStringvariableString

4

2 に答える 2

0
newInstance(this, variableString);
于 2013-06-23T00:40:59.690 に答える