5

我想测试一个存在于私有内部类中的私有方法

 public class MyBigClass {
    private class MyInnerClass {
       private void wantedMethod() {
       }
    }
 }

我想打电话wantedMethod() 来测试它

这是我的代码

Class[] classes = MyBigClass.class.getDeclaredClasses();
    for (int i = 0; i < classes.length; i++) {
        // this code print "MyInnerClass"
        System.out.println(">> inner classes >> " + classes[i].getSimpleName());
        if (classes[i].getSimpleName().equals("MyInnerClass")) {
            Class clazz = classes[i];
            // Constructor c=clazz.getConstructor();
            Method[] methods = clazz.getDeclaredMethods();
            // this code print "wantedMethod"
            for (int j = 0; j < methods.length; j++) {
                System.out.println("inner class methods >>  " + methods[i].getName());
            }

        }

    }    

问题:我不能打电话wantedMethod()

4

2 回答 2

6

如果你想调用一个非静态方法,你需要告诉你要调用哪个对象。在您的情况下,您需要内部类对象,但由于您还没有,因此您需要创建它。由于 Java 不能在没有外部类对象的情况下创建内部类对象,因此您也需要创建该外部对象。

所以这些是你需要采取的步骤:

  • 创建外部类对象(如果你没有),
  • 使用外部类对象创建内部类对象,
  • 在内部类对象上调用方法。

您可以这样做:(
您只需要记住默认构造函数与其类的可见性具有相同的可见性,因此私有类将具有私有构造函数,我们需要先使其可访问才能使用它)

try {
    //creating parent object
    Object outer = new MyBigClass();

    //creating inner class object
    Class<?> innerClass = Class.forName("MyBigClass$MyInnerClass");
    Constructor<?> constructor = innerClass.getDeclaredConstructor(MyBigClass.class);//inner object must know type of outer class
    constructor.setAccessible(true);//private inner class has private default constructor
    Object child = constructor.newInstance(outer);//inner object must know about its outer object

    //invoking method on inner class object
    Method method = innerClass.getDeclaredMethod("wantedMethod",new Class<?>[]{});
    method.setAccessible(true);//in case of unaccessible method
    method.invoke(child,new Object[]{});

} catch (ClassNotFoundException | NoSuchMethodException | SecurityException | InstantiationException | IllegalAccessException | IllegalArgumentException | InvocationTargetException e1) {
    // TODO Auto-generated catch block
    e1.printStackTrace();
}

您可以在此问题中找到有关通过反射创建内部类对象的更多信息

于 2012-05-16T15:41:12.510 回答
2

这是因为您的班级没有命名CodeCircuit。删除该if条件,它将起作用。

还要删除该行Constructor c=clazz.getConstructor();,因为它会引发异常。

进行这些更改后,您自己的代码将打印出来

>> inner classes >> MyInnerClass
inner class methods >>  wantedMethod

编辑

使用此代码执行该方法。

    Class<?>[] classes = MyBigClass.class.getDeclaredClasses();

    for (Class<?> clazz : classes) {
        if(clazz.getSimpleName().equals("MyInnerClass")) {
            Method method = clazz.getDeclaredMethod("wantedMethod", new Class[] {});
            method.setAccessible(true);
            method.invoke(clazz.getDeclaredConstructor(MyBigClass.class).newInstance(new MyBigClass()), new Object[] {});
        }
    }

语法有点奇怪,让您使用外部类来获取内部类构造函数。它的行为就像你有一个在你的内部类中定义的具有以下签名的构造函数:

public MyInnerClass(MyBigClass bigClass) {
}

但是,我认为这就是 Java 使用反射处理内部(嵌套)类的方式。

请注意,您必须public为内部类提供构造函数。

public class MyBigClass {
    private class MyInnerClass {
        public MyInnerClass() {
            System.out.println("hello");
        }
        private void wantedMethod() {
            System.out.println("world");
        }
    }
}

您还必须setAccessible(true)使用私有方法才能调用它。

编辑 2

经过进一步调查,当我反编译生成的MyBigClass$MyInnerClass.class类时,我发现我的预感是对的:

public class MyBigClass$MyInnerClass {
    public MyBigClass$MyInnerClass(MyBigClass paramMyBigClass) {
        System.out.println("hello");
    }
    private void wantedMethod() {
        System.out.println("world");
    }
}

如果有人可以对这种行为有所了解,那将非常高兴

于 2012-05-16T11:34:27.127 回答