为什么getDeclaredMethod with Class as second param会抛出NoSuchMethodException?

时间:2017-12-17 01:39:02

标签: java reflection junit

我想使用反射测试私有方法。在这种情况下,来自isEdible类的Food方法。

public class Food {

  private Boolean isEdible() {
    return true;
  }
}

当我在没有指定Food类的情况下使用getDeclaredMethod时,它已成功运行。

@Test
  public void foodTestOne() throws Exception {
    Food food = new Food();
    Method method = food.getClass().getDeclaredMethod("isEdible");
    method.setAccessible(true);
    boolean isEdible = (boolean) method.invoke(food);
    assertTrue(isEdible);
  }

但是当我在第二个参数上添加Food Class时,我得到了NoSuchMethodException

@Test
  public void foodTestTwo() throws Exception {
    Food food = new Food();
    Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);
    // execution stop here
  }

我的问题是:

  1. 我应该在第二个参数中添加什么才能使其正常工作?更改getDeclaredMethod("isEdible", Boolean.class)仍会引发相同的异常。
  2. 这看起来非常基本和直观,为什么会发生这种情况?

3 个答案:

答案 0 :(得分:1)

getDeclaredMethod需要匹配方法所期望的参数类型。当方法不带参数(例如isEdible())时,您可以传递null(或空Class[]),例如

public class Food {

    private Boolean isEdible() {
        return true;
    }

    public static void main(String[] args) {
        Food food = new Food();
        try {
            Class<?>[] methodArgumentTypes = null; // {};
            Object[] methodArguments = null; // new Object[0];
            Method method = food.getClass().getDeclaredMethod("isEdible", 
                    methodArgumentTypes);
            System.out.println(method.invoke(food, methodArguments));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

实际上会调用isEdible()并输出true

答案 1 :(得分:1)

如果方法没有参数,可以这样做:

obj.getClass().getDeclaredMethod(methodName, (Class<?>[]) null).invoke(obj);

Read more...

答案 2 :(得分:0)

您遇到的问题是在

行中
Method method = food.getClass().getDeclaredMethod("isEdible", Food.class);

您指定Food作为方法的参数;它不是。相反,你应该

Method method = food.getClass().getDeclaredMethod("isEdible");

isEdible()被声明为私有,因此即使使用getDeclaredMethod,您也无法在当前上下文中访问它。要允许访问,可以在调用方法之前将其设置为可访问。

method.setAccessible(true);
method.invoke(food);