为什么 Class.newInstance 总是抛出异常?
Why does Class.newInstance always throw an exception?
我想定义一个自定义 class 加载程序以在运行时加载我自己的 class。
然而,即使我定义了零参数构造函数,Class.newInstance
总是失败。
异常信息为:
java.lang.IllegalAccessException: Class 你好无法访问 class 的成员 用修饰符测试 "public"
为什么?
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
class 是使用默认(包)范围声明的,但是在运行时,您的 Hello
和 Test
class es在不同的包中。
Java 中 class 的名称(唯一标识符)是完全限定的 class 名称 和 class 的组合加载它的加载器:
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
class 正在由下游 class 加载器加载,因此它的(默认)包不被认为是相同的(默认) Hello
(由系统 class 加载程序加载)所在的包。因此,您无权访问构造函数,因为 class 本身不是 public。
如果您将 Test
设为单独的 public 顶级 class 或使用反射使其可用,则此示例将有效。
您需要制作 class public:
public class Test { ... }
或者,获取对构造函数的引用并使其可访问:
Constructor<?> constructor = c.getConstructor();
constructor.setAccessible(true);
Object o = constructor.newInstance();
我想定义一个自定义 class 加载程序以在运行时加载我自己的 class。
然而,即使我定义了零参数构造函数,Class.newInstance
总是失败。
异常信息为:
java.lang.IllegalAccessException: Class 你好无法访问 class 的成员 用修饰符测试 "public"
为什么?
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
class 是使用默认(包)范围声明的,但是在运行时,您的 Hello
和 Test
class es在不同的包中。
Java 中 class 的名称(唯一标识符)是完全限定的 class 名称 和 class 的组合加载它的加载器:
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
class 正在由下游 class 加载器加载,因此它的(默认)包不被认为是相同的(默认) Hello
(由系统 class 加载程序加载)所在的包。因此,您无权访问构造函数,因为 class 本身不是 public。
如果您将 Test
设为单独的 public 顶级 class 或使用反射使其可用,则此示例将有效。
您需要制作 class public:
public class Test { ... }
或者,获取对构造函数的引用并使其可访问:
Constructor<?> constructor = c.getConstructor();
constructor.setAccessible(true);
Object o = constructor.newInstance();