Java 为什么Class.newInstance总是抛出异常?

Java 为什么Class.newInstance总是抛出异常?,java,exception,reflection,constructor,runtime-error,Java,Exception,Reflection,Constructor,Runtime Error,我想定义一个自定义类加载器,以便在运行时加载我自己的类 然而,Class.newInstance总是失败,即使我定义了零参数构造函数 例外消息是: java.lang.IllegalAccessException:Class Hello无法访问修饰符为“public”的类测试成员 为什么? import java.io.BufferedInputStream; 导入java.io.ByteArrayOutputStream; 导入java.io.IOException; 导入java.lang.

我想定义一个自定义类加载器,以便在运行时加载我自己的类

然而,
Class.newInstance
总是失败,即使我定义了零参数构造函数

例外消息是:

java.lang.IllegalAccessException:Class Hello无法访问修饰符为“public”的类测试成员

为什么?

import java.io.BufferedInputStream;
导入java.io.ByteArrayOutputStream;
导入java.io.IOException;
导入java.lang.reflect.InvocationTargetException;
导入java.lang.reflect.Method;
导入java.util.HashMap;
导入java.util.Map;
类CustomClassLoader扩展了类加载器{
私人地图>();
公共字符串toString(){
返回CustomClassLoader.class.getName();
}
@凌驾
受保护类findClass(字符串名称)引发ClassNotFoundException{
if(类.容器(名称)){
返回类。get(name);
}
字节[]类数据;
试一试{
classData=loadClassData(名称);
}捕获(IOE异常){
抛出新的ClassNotFoundException(“类[”+名称
+“]找不到”,e);
}
c类=定义类(名称,类数据,0,类数据.length);
(c)级;
类。put(名称,c);
返回c;
}
私有字节[]loadClassData(字符串名称)引发IOException{
BufferedInputStream in=新的BufferedInputStream(
ClassLoader.getSystemResourceAsStream(名称.replace(“.”,“/”)
+“.class”);
ByteArrayOutputStream out=新建ByteArrayOutputStream();
int i;
而((i=in.read())!=-1){
写出(i);
}
in.close();
byte[]classData=out.toByteArray();
out.close();
返回类数据;
}
}
课堂测试
{
公开考试()
{}
公共空间
{}
}
公共课你好{
公共静态void main(字符串[]args)
{
试一试{
CustomClassLoader=新CustomClassLoader();
类c=loader.findClass(“Test”);//好!
对象o=c.newInstance();//总是失败!
}
捕获(例外e)
{ 
字符串s=e.getMessage();
//s是“java.lang.IllegalAccessException:类Hello无法访问”
//具有修饰符“public”的类测试的成员
}
}
}

问题在于,您的
测试
类是使用默认(包)范围声明的,但是在运行时,您的
Hello
测试
类位于不同的包中

Java中类的名称(唯一标识符)是完全限定类名和加载它的类加载器的组合:

在运行时,类或接口不是由其名称决定的,而是由一对名称决定的:它的二进制名称(§4.2.1)和它的定义类加载器。每个这样的类或接口都属于一个运行时包。类或接口的运行时包由类或接口的包名和定义类加载器决定

在这种情况下,
Test
类由下游类加载器加载,因此其(默认)包不被视为与
Hello
(由系统类加载器加载)所在的(默认)包相同。因此,您无权访问构造函数,因为类本身不是公共的


如果将
Test
设置为一个单独的公共顶级类,或者使用反射使其可用,则此示例将起作用。

您需要将该类设置为公共类:

public class Test { ... }
或者,获取对构造函数的引用并使其可访问:

Constructor<?> constructor = c.getConstructor();
constructor.setAccessible(true);
Object o = constructor.newInstance();
Constructor=c.getConstructor();
constructor.setAccessible(true);
对象o=constructor.newInstance();

异常的堆栈跟踪说明了什么?你读过了吗?因为你要找的信息就在那里。现在,堆栈跟踪是隐藏的,因为您捕获异常并忽略它。不要这样做。我怀疑问题在于,
Test
类是由下游类加载器加载的,您可以从该加载器尝试创建一个新实例。我猜,
Test
Hello
在不同的包或默认包中。@PeterLawrey不,它们都在同一个文件中(在默认包中)。永远不要使用默认包。问题不在于构造函数,而在于类本身。哇,确实如此,但你知道为什么需要这样做吗?我可以修改类,使已经公开的构造函数不再公开吗?在我的情况下,内部类不是静态的
Constructor<?> constructor = c.getConstructor();
constructor.setAccessible(true);
Object o = constructor.newInstance();