java - “类加载器创建的对象的方法和构造函数可能引用其他类”是什么意思?
问题描述
问题中的内容(“类加载器创建的对象的方法和构造函数可能引用其他类”)引用自ClassLoader 的JavaDoc。
虽然后面有一个例子,但我还是看不懂。你能给我一个会因此导致错误的例子吗?
多谢。
解决方案
“类加载器创建的对象的方法和构造函数可能会引用其他类”
这仅仅意味着一个类可能有对其他类的引用。因此,类加载器也必须负责加载引用的类。
让我们定义两个简单的类。TestReference
具有方法的类foo
:
public class TestReference {
public void foo() {
System.out.println("Hello world");
}
}
以及在其构造函数中TestClass
实例化的类:TestReference
public class TestClass {
public TestClass() {
TestReference reference = new TestReference();
reference.foo();
}
}
现在我们定义一个从.class
文件加载类的自定义类加载器:
public class MyClassLoader extends ClassLoader {
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
// Ignore this for the example as Object is always implicitly referenced by a class
if("java.lang.Object".equals(name)) {
return super.loadClass(name);
}
System.out.println("Loading class: " + name);
// Load class from "/path/to/my/classes/TestClass.class"
Path fileLocation = Paths.get("/path/to/my/classes/" + name + ".class");
try {
byte[] classData = Files.readAllBytes(fileLocation);
Class<?> clazz = defineClass(name, classData, 0, classData.length);
// Class has been successfully loaded and defined by the classloader
System.out.println("Loaded: " + clazz.getSimpleName());
return clazz;
} catch (IOException e) {
// Class could not be found
throw new ClassNotFoundException();
}
}
}
例如编译TestReference.java
和TestClass.java
使用javac
并仅移动TestClass.class
到/path/to/my/classes/
“为了确定引用的类,Java 虚拟机调用最初创建该类的类加载器的 loadClass 方法。”
以下将失败,因为类加载器会传递地尝试查找和加载TestReference.class
,但它不会在指定的位置找到它:
public static void main(String[] args) {
ClassLoader classLoader = new MyClassLoader();
try {
Object o = classLoader.loadClass("TestClass").newInstance();
} catch (ClassNotFoundException | IllegalAccessException | InstantiationException e) {
e.printStackTrace();
}
}
控制台输出:
Loading class: TestClass
Loaded: TestClass
Loading class: TestReference
Exception in thread "main" java.lang.NoClassDefFoundError: TestReference
要修复此错误,请移至TestReference.class
并/path/to/my/classes/
调整类加载器loadClass
,如下所示:
if("java.lang.Object".equals(name) ||
"java.lang.System".equals(name) ||
"java.io.PrintStream".equals(name)) {
return super.loadClass(name);
}
推荐阅读
- html - Div 远远超出模态,希望它留在内部并滚动
- r - 如何以特定模式从字符串中删除单词并保留第一个数字
- python - 切片以删除列表中间的项目
- list - 如何将元组列表转换为单个列表
- ios - 如何正确传递 texture2d_array
到片段着色器? - iis - Delphi 10.3 RAD 服务器:无法从浏览器访问托管在 Windows Server 2016 IIS (ISAPI dll) 上的资源端点
- python - Python - BS4 - 如何获取未包含在 html 标签中的文本
- neo4j - Neo4J CSV 转换成道具
- java - 使用 gradle 4 构建签名的发布 apk 失败
- java - 开始编码器 (Java) - 验证字符串输入并在输入正确输入后结束循环