什么是";由类加载器创建的对象的方法和构造函数可以引用其他类"";刻薄



问题中的内容("类加载器创建的对象的方法和构造函数可以引用其他类"(引用自ClassLoader的JavaDoc。

虽然后面有一个例子,但我还是不能理解。你能给我举一个会因此而出错的例子吗?

非常感谢。

"类加载器创建的对象的方法和构造函数可以参考其他类别">

这只是意味着一个类可能具有对其他类的引用。因此,类加载器也必须负责加载引用的类。

让我们定义两个简单的类。具有方法foo:的类TestReference

public class TestReference {
public void foo() {
System.out.println("Hello world");
}
}

以及在其构造函数中实例化CCD_ 4的类CCD_

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();
}
}
}

例如,使用javac编译TestReference.javaTestClass.java,并仅将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);
}

最新更新