IllegalAccessException
异常信息
1
2
3
4
5
6
7
|
Exception in thread "main" java.lang.IllegalAccessException: Class fluffy.mo.MyClassloader can not access a member of class fluffy.mo.Car with modifiers "public"
at sun.reflect.Reflection.ensureMemberAccess(Reflection.java:102)
at java.lang.reflect.AccessibleObject.slowCheckMemberAccess(AccessibleObject.java:296)
at java.lang.reflect.AccessibleObject.checkAccess(AccessibleObject.java:288)
at java.lang.reflect.Constructor.newInstance(Constructor.java:413)
at fluffy.mo.MyClassloader.test4(MyClassloader.java:91)
at fluffy.mo.MyClassloader.main(MyClassloader.java:68)
|
在使用反射创建对象时,被提示没权限
代码示例
1
2
3
|
package fluffy.mo;
public class Person{
}
|
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
|
package fluffy.mo;
import java.io.File;
import java.io.FileInputStream;
import java.io.InputStream;
import java.lang.reflect.Method;
public class MyClassloader extends ClassLoader {
private byte[] getData(String name) throws Exception {
String path = getClass().getResource("/").getPath();
path = path + name.replace(".", "/") + ".class";
InputStream in = new FileInputStream(new File(path));
byte[] data = new byte[in.available()];
in.read(data);
in.close();
return data;
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
byte[] data = null;
try {
data = this.getData(name);
} catch (Exception e) {
e.printStackTrace();
throw new ClassNotFoundException();
}
Class<?> aClass = defineClass(name, data, 0, data.length);
return aClass;
}
static void test1() throws Exception {
MyClassloader c1 = new MyClassloader();
String name = "fluffy.mo.Person";
Class pCls = c1.findClass(name);
Person p1 = new Person();
Object p2 = pCls.getConstructor().newInstance();
// Person p3 = (Person)p2;
// 强转报错,虽然二者都是Person对象,但二者的类加载器不同
System.out.println("test1-done");
}
public static void main(String[] args) throws Exception {
// 加载类的时候没有调用 loadClass 方法, 而是 findClass
// 否则会有父类委托,导致每次都由AppClassLoader加载
test1();
Class carCls = null;
Car car1 = new Car();
String carName = "fluffy.mo.Car";
// 方式一
carCls = Class.forName(carName);
carCls.newInstance();
// carCls.getConstructor().newInstance();
// 方式二
carCls = Class.forName(carName, true, new MyClassloader());
carCls.getConstructor().newInstance();
// 方式三
MyClassloader classloader1 = new MyClassloader();
carCls = classloader1.findClass(carName);
// test4(carCls); // error
// 方式四: 为了解决方式三的报错
Class classUtil = classloader1.findClass("fluffy.mo.MyClassloader");
ClassLoader classloaderObj = (ClassLoader) classUtil.newInstance();
// classloader1与
// classloader1的类文件由AppClassloader加载,而classloaderObj的类文件由classloader1加载
Method[] methods = classUtil.getMethods();
for (Method method : methods) {
if ("test4".equals(method.getName())) {
method.invoke(classloaderObj, carCls);
}
}
System.out.println("test-66-done");
}
public static void test4(Class carCls) throws Exception {
Object p2 = carCls.getConstructor().newInstance();
System.out.println(p2.getClass().getClassLoader());
System.out.println(p2);
}
}
// 在没有显示声明空构造函数的情况下,通过反射创建实例也会有不同的结果
class Car {
static {
System.out.println("init car");
}
public Car() {
}
}
|
原因
由于Car没有声明public导致在反射创建对象时,存在权限问题。
为何方式四的carCls.getConstructor().newInstance()不报错,方式三报错呢
因为方式四在创建Car对象时,test方法和Car类二者在同一个包名下,有权限访问
方式三,test4方法的类由AppClassloader加载, carCls由classloader1加载,虽然二者包名相同,但隔着类加载器
方式三的问题也可以给Car加上public 声明解决
方式二是为啥成功了,因为方式二其实走的loadClass方法,会进行父类委托,返回的class其实是由AppClassloader加载的
文章作者
duansheli
上次更新
2019-12-25
(325c7b3)