如何使用反射(Java)调用私有静态方法?

时间:2011-01-22 20:38:08

标签: java reflection invoke

我想调用私有静态方法。我有它的名字。我听说可以使用Java反射机制完成它。我该怎么办?

编辑:尝试调用方法时遇到的一个问题是如何指定其参数的类型。我的方法接收一个参数,其类型是Map。因此我无法做Map<User, String>.TYPE(在运行时因为Java类型擦除而没有Map这样的东西)。是否有其他方法可以获得该方法?

5 个答案:

答案 0 :(得分:95)

假设您要调用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

答案 1 :(得分:9)

reflection tutorial

调用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();
    }
    }
}

答案 2 :(得分:2)

不,你不能说Map<K,V>.class。这是因为类型擦除。在运行时,没有这样的东西。

幸运的是,你可以说出普通的Map.class。它在运行时都是一样的。

如果警告困扰您,请搜索与泛型和类型擦除相关的其他问题,此处有关于此主题的大量信息。

答案 3 :(得分:1)

我使用一个封装获取目标方法然后调用它的方法。当然可能有一些限制。这是放入类的方法及其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));

    }
}

}

答案 4 :(得分:0)

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

可能会抛出许多已检查的异常。参数类型和参数都是椭圆形参数(可变长度),根据需要填充它们。规范的JVM具有强类型调用约定,因此您需要知道参数类型。

话虽如此,除非您正在编写某种应用程序容器,服务器组件容器,类似RMI的系统或基于JVM的语言,否则您应该避免这样做。