简体   繁体   中英

How do I invoke a private static method using reflection (Java)?

I would like to invoke a private static method. I have its name. I've heard it can be done using Java reflection mechanism. How can I do it?

EDIT: One problem I encountered when trying to invoke the method is how to specify the type of its argument. My method receives one argument and its type is Map. Therefore I cannot do Map<User, String>.TYPE (In run time there's no such a thing as Map because of Java Type erasure). Is there another way to get the method?

Let's say you want to call 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

Invoke main from reflection tutorial

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

No, you can't say Map<K,V>.class . This is because of type erasure . At runtime, there's no such thing.

Luckily, you can say just plain old Map.class . It's all the same at runtime.

If the warnings bother you, search for other questions related to generics and type erasure, there's a wealth of information on the subject here.

I use a single method that encapsulates getting the target method and then invoking it. Probably has some limitations, of course. Here is the method put into a class and its JUnit test:

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));

    }
}

}

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

There are a number of checked exceptions which may be thrown. Both parameterTypes and parameters are ellipse arguments (variable length), fill them in as needed. The JVM by specification has a strongly typed calling convention so you need to know the parameter types.

With that said, unless you are writing some sort of application container, server component container, RMI-like system, or JVM based langauge you should avoid doing this.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM