
package com.prac; public class outer { int i = 1; private static class staticInner{ int j = 2; staticInner(){} void print(){ System.out.println("in staticInner"); } } private class normalInner{ int k =3; void print(){ System.out.println("in normalInner"); } } } 外部类,里面有一个静态内部类,非静态内部类,它们都是私有的。
import java.lang.reflect.Constructor; import java.lang.reflect.InvocationTargetException; import com.prac.outer; public class test2 { public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException { outer ooo = new outer(); Class<?> clazz = null; try { clazz = Class.forName("com.prac.outer$normalInner"); System.out.println(clazz.getName()); } catch (ClassNotFoundException e) { e.printStackTrace(); } Constructor<?> con = clazz.getDeclaredConstructor(); Object obj = con.newInstance(); } } 有一个测试类,我想试试用反射来创建私有的内部类实例,因为内部类是权限是私有的,所以获得 Class 引用只能通过 forName (不然就可以 import 这个内部类,然后通过类名.class来获得了)。
当 31 行,为clazz = Class.forName("com.prac.outer$normalInner")即获得非静态内部类 Class 的引用,然后 newInstance 报错:
com.prac.outer$normalInner Exception in thread "main" java.lang.NoSuchMethodException: com.prac.outer$normalInner.<init>() at java.base/java.lang.Class.getConstructor0(Class.java:3354) at java.base/java.lang.Class.getDeclaredConstructor(Class.java:2558) at test2.main(test2.java:38) 看起来好像是这篇博客讲的原因: https://www.jianshu.com/p/ecda088dcc5f 即非静态内部类构造时,构造函数会隐式地加一个 this 即外部类的引用。但这种情况还有解决办法吗?
当 31 行为clazz = Class.forName("com.prac.outer$staticInner")即获得静态内部类 Class 的引用,然后 newInstance 报错:
com.prac.outer$staticInner Exception in thread "main" java.lang.IllegalAccessException: class test2 cannot access a member of class com.prac.outer$staticInner with modifiers "" at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:376) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:639) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:490) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) at test2.main(test2.java:39) 为什么这个就直接报错,有标识符的成员类就无法访问,因为是静态内部类吗?这种情况还有解决办法吗?
1 shily 2019 年 7 月 22 日 测试一下就知道了啊,错误报在 getDeclaredConstructor(),这个是返回无参数的构造上。你已经通过博客知道,默认的非静态内部类会捕获外部类引用。 通过 clazz.getDeclaredConstructors() 可以知道它有一个构造,<init>(com.prac.outer),所以很容易修正啊。 通过 Constructor<?> con = clazz.getDeclaredConstructor(outer.class); 来获取构造方法 调用时是 Object obj = con.newInstance(ooo); |
2 amiwrong123 OP @shily 好吧,原来是我 getDeclaredConstructor 用的不对,谢谢回答啦。 但是,现在就报错: com.prac.outer$normalInner Exception in thread "main" java.lang.IllegalAccessException: class test2 cannot access a member of class com.prac.outer$normalInner with modifiers "private" at java.base/jdk.internal.reflect.Reflection.newIllegalAccessException(Reflection.java:376) at java.base/java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:639) at java.base/java.lang.reflect.Constructor.newInstanceWithCaller(Constructor.java:490) at java.base/java.lang.reflect.Constructor.newInstance(Constructor.java:481) at test2.main(test2.java:39) 所以不管是静态内部类还是非静态内部类,只要访问权限是私有,就不可以创建实例了吗 |
3 bringyou 2019 年 7 月 22 日 contructor.setAccessible(true) |
4 codeyung 2019 年 7 月 22 日 setAccessible |
5 amiwrong123 OP @bringyou 好吧,现在成功了。谢谢回答啦。 Constructor<?> con = clazz.getDeclaredConstructor(outer.class); con.setAccessible(true); Object obj = con.newInstance(ooo); 但这种情况下,我是不是只能用 Object 引用来指向这个实例,因为没法 import 私有内部类,所以也无法用私有内部类类型来声明变量了? |
6 palmers 2019 年 7 月 23 日 这种情况出现的原因,我认为有两方面: 1. 内部类实例化无参构造是有一个影藏参数就是外部类指针 this, 所以其实不是相比正常的无参构造它并不是无参构造; 非 static 需要先实例化外部类,所以需要这样: ```java outer ot = new outer(); Class<?> clazz = Class.forName("com.prac.outer$normalInner"); Constructor<?> cOnstructor= clazz.getDeclaredConstructor(outer.class); Object o = constructor.newInstance(ot); ``` 2. 对于私有类或方法外部访问都是拒绝的, 需要解决访问权限问题; 以上问题解决了, 我想基本不会有问题了,希望能帮到你 |
7 helloSpringBoot 2019 年 7 月 23 日 @amiwrong123 私有的目的不就是这样吗。。。。 |
8 amiwrong123 OP |