"The methods and constructors of objects created by a class loader may reference other classes" 是什么意思?
what does "The methods and constructors of objects created by a class loader may reference other classes" mean?
问题("The methods and constructors of objects created by a class loader may reference other classes")中的内容引用自JavaDoc of ClassLoader.
后面虽然有例子,还是看不懂。能否请你举个例子,因为这个会导致错误?
非常感谢。
"The methods and constructors of objects created by a class loader may
reference other classes"
这只是意味着 class 可能引用了其他 classes。因此,classloader 还必须负责加载引用的 classes。
让我们定义两个简单的 classes。 class TestReference
方法 foo
:
public class TestReference {
public void foo() {
System.out.println("Hello world");
}
}
和一个 class TestClass
在其构造函数中实例化 TestReference
:
public class TestClass {
public TestClass() {
TestReference reference = new TestReference();
reference.foo();
}
}
现在我们定义一个自定义 classloader 从 .class
文件加载 classes:
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.java
和 TestClass.java
,仅将 TestClass.class
移动到 /path/to/my/classes/
"To determine the class(es) referred to, the Java virtual machine invokes the loadClass method of the class loader that originally created the class."
以下将失败,因为 classloader 传递性地尝试查找和加载 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/
并调整 classloader 的 loadClass
如下:
if("java.lang.Object".equals(name) ||
"java.lang.System".equals(name) ||
"java.io.PrintStream".equals(name)) {
return super.loadClass(name);
}
问题("The methods and constructors of objects created by a class loader may reference other classes")中的内容引用自JavaDoc of ClassLoader.
后面虽然有例子,还是看不懂。能否请你举个例子,因为这个会导致错误?
非常感谢。
"The methods and constructors of objects created by a class loader may reference other classes"
这只是意味着 class 可能引用了其他 classes。因此,classloader 还必须负责加载引用的 classes。
让我们定义两个简单的 classes。 class TestReference
方法 foo
:
public class TestReference {
public void foo() {
System.out.println("Hello world");
}
}
和一个 class TestClass
在其构造函数中实例化 TestReference
:
public class TestClass {
public TestClass() {
TestReference reference = new TestReference();
reference.foo();
}
}
现在我们定义一个自定义 classloader 从 .class
文件加载 classes:
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.java
和 TestClass.java
,仅将 TestClass.class
移动到 /path/to/my/classes/
"To determine the class(es) referred to, the Java virtual machine invokes the loadClass method of the class loader that originally created the class."
以下将失败,因为 classloader 传递性地尝试查找和加载 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/
并调整 classloader 的 loadClass
如下:
if("java.lang.Object".equals(name) ||
"java.lang.System".equals(name) ||
"java.io.PrintStream".equals(name)) {
return super.loadClass(name);
}