首页 > 解决方案 > “类加载器创建的对象的方法和构造函数可能引用其他类”是什么意思?

问题描述

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

虽然后面有一个例子,但我还是看不懂。你能给我一个会因此导致错误的例子吗?

多谢。

标签: javajvm

解决方案


“类加载器创建的对象的方法和构造函数可能会引用其他类”

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

让我们定义两个简单的类。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.javaTestClass.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);
}

推荐阅读