如何调用私有内部类中存在的私有方法

时间:2012-05-16 11:27:54

标签: java reflection private-methods

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

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

2 个答案:

答案 0 :(得分: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();
}

您可以在this question

中找到有关通过反射创建内部类对象的更多信息

答案 1 :(得分: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");
    }
}

如果有人能对这种行为有所启发,那真的很高兴