我想定义一个自定义类加载器来在运行时加载我自己的类。
但是,Class.newInstance
即使我定义了一个零参数的构造函数,也总是失败。
异常消息是:
java.lang.IllegalAccessException: 类 Hello 无法使用修饰符“public”访问 Test 类的成员
为什么?
import java.io.BufferedInputStream;
import java.io.ByteArrayOutputStream;
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.HashMap;
import java.util.Map;
class CustomClassLoader extends ClassLoader {
private Map<String, Class<?>> classes = new HashMap<String, Class<?>>();
public String toString() {
return CustomClassLoader.class.getName();
}
@Override
protected Class<?> findClass(String name) throws ClassNotFoundException {
if (classes.containsKey(name)) {
return classes.get(name);
}
byte[] classData;
try {
classData = loadClassData(name);
} catch (IOException e) {
throw new ClassNotFoundException("Class [" + name
+ "] could not be found", e);
}
Class<?> c = defineClass(name, classData, 0, classData.length);
resolveClass(c);
classes.put(name, c);
return c;
}
private byte[] loadClassData(String name) throws IOException {
BufferedInputStream in = new BufferedInputStream(
ClassLoader.getSystemResourceAsStream(name.replace(".", "/")
+ ".class"));
ByteArrayOutputStream out = new ByteArrayOutputStream();
int i;
while ((i = in.read()) != -1) {
out.write(i);
}
in.close();
byte[] classData = out.toByteArray();
out.close();
return classData;
}
}
class Test
{
public Test()
{}
public void Hello()
{}
}
public class Hello {
public static void main(String[] args)
{
try {
CustomClassLoader loader = new CustomClassLoader();
Class<?> c = loader.findClass("Test"); // OK!
Object o = c.newInstance(); // ALWAYS FAIL!
}
catch (Exception e)
{
String s = e.getMessage();
// s is "java.lang.IllegalAccessException: Class Hello can not access"
// " a member of class Test with modifiers "public""
}
}
}
最佳答案
问题是您的 Test
类以默认(包)范围声明,但在运行时,您的 Hello
和 Test
类在不同的包中。
Java 中类的名称(唯一标识符)是完全限定的类名和加载它的类加载器的组合:
At run time, a class or interface is determined not by its name alone, but by a pair: its binary name (§4.2.1) and its defining class loader. Each such class or interface belongs to a single run-time package. The run-time package of a class or interface is determined by the package name and defining class loader of the class or interface. (JVMS 5.3)
在这种情况下,
Test
类正在由下游类加载器加载,因此它的(默认)包不被视为与 Hello
相同的(默认)包(由系统类加载器加载)在其中。因此,您无权访问构造函数,因为类本身不是公共(public)的。如果您使用
Test
,则此示例将有效。一个单独的公共(public)顶级类或使用反射使其可用。
关于java - 为什么 Class.newInstance 总是抛出异常?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/27764018/