web-dev-qa-db-ja.com

リフレクション(Java)を使用してプライベート静的メソッドを呼び出すにはどうすればよいですか?

プライベート静的メソッドを呼び出したいです。名前があります。 Javaリフレクションメカニズムを使用して実行できると聞きました。どうすればできますか?

EDIT:メソッドを呼び出そうとしたときに発生した問題の1つは、引数の型を指定する方法です。私のメソッドは1つの引数を受け取り、そのタイプはMapです。したがって、Map<User, String>.TYPE(実行時には、Java Type erasure)のためMapのようなものはありません。メソッドを取得する別の方法はありますか?

56
snakile

MyClass.myMethod(int x);を呼び出したいとしましょう。

Method m = MyClass.class.getDeclaredMethod("myMethod", Integer.TYPE);
m.setAccessible(true); //if security settings allow this
Object o = m.invoke(null, 23); //use null if the method is static
98
Landei

リフレクションチュートリアル からmainを呼び出します

import Java.lang.reflect.InvocationTargetException;
import Java.lang.reflect.Method;
import Java.util.Arrays;

public class InvokeMain {
    public static void main(String... args) {
    try {
        Class<?> c = Class.forName(args[0]);
        Class[] argTypes = new Class[] { String[].class };
        Method main = c.getDeclaredMethod("main", argTypes);
        String[] mainArgs = Arrays.copyOfRange(args, 1, args.length);
        System.out.format("invoking %s.main()%n", c.getName());
        main.invoke(null, (Object)mainArgs);

        // production code should handle these exceptions more gracefully
    } catch (ClassNotFoundException x) {
        x.printStackTrace();
    } catch (NoSuchMethodException x) {
        x.printStackTrace();
    } catch (IllegalAccessException x) {
        x.printStackTrace();
    } catch (InvocationTargetException x) {
        x.printStackTrace();
    }
    }
}
9
Cratylus

いいえ、あなたは言うことができませんMap<K,V>.class。これは、type erasureが原因です。実行時には、そのようなことはありません。

幸いなことに、あなたはcanただ昔ながらのMap.class。実行時にすべて同じです。

警告が気になる場合、ジェネリックおよびタイプの消去に関連する他の質問を検索してください。ここには、このテーマに関する豊富な情報があります。

2
bmargulies

ターゲットメソッドの取得と呼び出しをカプセル化する単一のメソッドを使用します。もちろん、いくつかの制限があります。以下は、クラスに入れられたメソッドとそのJUnitテストです。

public class Invoker {
/**
 * Get method and invoke it.
 * 
 * @author jbetancourt
 * 
 * @param name of method
 * @param obj Object to invoke the method on
 * @param types parameter types of method
 * @param args to method invocation
 * @return return value
 * @throws Exception for unforseen stuff
 */
public static final <T> Object invokeMethod(final String name, final T obj,
  final Class<?>[] types, final Object... args) throws Exception {

    Method method = obj.getClass().getDeclaredMethod(name, types);
    method.setAccessible(true);
    return method.invoke(obj, args);
}

/**
 * Embedded JUnit tests.
 */
@RunWith(JUnit4.class)
public static class InvokerTest {
    /** */
    @Test
    public void testInvoke() throws Exception {
        class TestTarget {
            private String hello() {
                return "Hello world!";
            }
        }

        String actual = (String) Invoker.invokeMethod("hello",
                new TestTarget(), new Class<?>[] {});
        String expected = "Hello world!";
        assertThat(actual, is(expected));

    }
}

}

1
Josef.B
Object insecure; //This needs to be an initialized reference

Class c = insecure.getClass();
Method m = c.getMethod(name, parameterTypes); //Fill the name and types in
m.setAccessible(true);
m.invoke( insecure, parameters ); //Fill in the parameters you would like

スローされる可能性のあるチェック済みの例外がいくつかあります。 parameterTypesとparametersはどちらも楕円引数(可変長)であり、必要に応じて入力します。仕様によるJVMには、厳密に型指定された呼び出し規則があるため、パラメーターの型を知る必要があります。

そうは言っても、何らかのアプリケーションコンテナ、サーバーコンポーネントコンテナ、RMIに似たシステム、またはJVMベースの言語を記述しているのでなければ、これを行わないでください。

0
Mark