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-07-22 18:18:58 +08:00
测试一下就知道了啊,错误报在 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-07-22 21:25:57 +08:00
contructor.setAccessible(true)
|
4
codeyung 2019-07-22 23:41:04 +08:00
setAccessible
|
5
amiwrong123 OP @bringyou
好吧,现在成功了。谢谢回答啦。 Constructor<?> con = clazz.getDeclaredConstructor(outer.class); con.setAccessible(true); Object obj = con.newInstance(ooo); 但这种情况下,我是不是只能用 Object 引用来指向这个实例,因为没法 import 私有内部类,所以也无法用私有内部类类型来声明变量了? |
6
palmers 2019-07-23 10:20:53 +08:00
这种情况出现的原因,我认为有两方面:
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-07-23 10:27:35 +08:00
@amiwrong123 私有的目的不就是这样吗。。。。
|
8
amiwrong123 OP |