【问题标题】:How do I invoke a private static method using reflection (Java)?如何使用反射(Java)调用私有静态方法?
【发布时间】:2011-01-22 20:38:07
【问题描述】:

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

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

【问题讨论】:

  • 试试MyClass.class.getDeclaredMethod("myMethod", Map.class);为你的情况
  • 有趣的是,该方法的通用信息在运行时仍然可用。 Method.getGenericParameterTypes

标签: java reflection invoke


【解决方案1】:

假设你想调用 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

【讨论】:

  • 谢谢。我的方法接收一个参数,它的类型是 Map。因此我不能做'Map.TYPE'。有没有其他方法获取方法?
  • @snakile:try MyClass.class.getDeclaredMethod("myMethod", Map.class); 为你的情况
  • 如何使用(类、字符串等).type 进行更改?
  • @delive 通常你可以使用YourClass.class 作为参数,Integer.TYPE 只是原始类型的拐杖,没有真正的类。
  • 但是你将如何获得方法的返回值呢?由于它是静态的,因此不会保存在 o 中。
【解决方案2】:

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

【讨论】:

    【解决方案3】:

    不,你不能说Map&lt;K,V&gt;.class。这是因为类型擦除。在运行时,没有这样的事情。

    幸运的是,你可以说简单的老Map.class。在运行时都是一样的。

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

    【讨论】:

      【解决方案4】:

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

      }

      【讨论】:

        【解决方案5】:
        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 的语言,否则您应该避免这样做。

        【讨论】:

          猜你喜欢
          • 2019-09-02
          • 2012-08-08
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2018-10-30
          相关资源
          最近更新 更多