《深入Java虚拟机》第二版(很老的那本,Bill Venners写的,有中文翻译那本)第八章讲解类加载器用了个
Cindy、Mom、Grandma的例子。但那个例子是错的。
发了邮件到jdk6-dev邮件列表,等待答复。顺便发这边大家讨论。
那个例子说,Cindy的parent是Mom,Mom的parent是Grandma,Grandma的parent是null也就是bootstrap class loader。
Cindy尝试加载java.io.FileReader会委派给Mom,Mom委派给Grandma,Grandma委派给bootstrap,bootstrap成功加载并一层层把Class返回出来。
这个过程完成后,书上说Cindy、Mom、Grandma都应该是initiating loader。但事实却不是如此。
代码例子:
import java.io.*;
import java.net.*;
public class TestInitiatingLoader {
public static void main(String[] args) throws Exception {
Grandma grandma = new Grandma();
Mom mom = new Mom(grandma);
Cindy cindy = new Cindy(mom);
cindy.loadClass("Dummy").newInstance(); // force class init
final String reader = "java.io.FileReader";
printStats(grandma, reader); // false
printStats(mom, reader); // false
printStats(cindy, reader); // true
}
private static void printStats(LoadedClassQueryable loader, String name) {
System.out.printf("Is %s an initiating loader of %s: %b\n",
loader.getClass().getName(),
name,
loader.foundLoadedClass(name));
}
}
interface LoadedClassQueryable {
boolean foundLoadedClass(String name);
}
class Cindy
extends URLClassLoader
implements LoadedClassQueryable {
public Cindy(ClassLoader parent) {
super(makeArgs(), parent);
}
private static URL[] makeArgs() {
try {
return new URL[] { new File(".").toURI().toURL() };
} catch (Exception e) {
e.printStackTrace();
return new URL[] { };
}
}
@Override
public Class<?> loadClass(String name) throws ClassNotFoundException {
if ("Dummy".equals(name)) {
// force Cindy to load this Dummy class
return findClass("Dummy");
}
return super.loadClass(name);
}
@Override
public boolean foundLoadedClass(String name) {
return findLoadedClass(name) != null;
}
}
class Mom
extends ClassLoader
implements LoadedClassQueryable {
public Mom(ClassLoader parent) {
super(parent);
}
@Override
public boolean foundLoadedClass(String name) {
return findLoadedClass(name) != null;
}
}
class Grandma
extends ClassLoader
implements LoadedClassQueryable {
public Grandma() {
super(null); // use bootstrap class loader as parent
}
@Override
public boolean foundLoadedClass(String name) {
return findLoadedClass(name) != null;
}
}
Dummy.java
import java.io.*;
public class Dummy {
static {
// Dummy should be loaded by Cindy.
// So Cindy will be recorded as an initiating loader for java.io.FileReader
try {
new FileReader("Dummy.class").close();
} catch (Exception e) {
e.printStackTrace();
}
}
}
运行结果:
Is Grandma an initiating loader of java.io.FileReader: false
Is Mom an initiating loader of java.io.FileReader: false
Is Cindy an initiating loader of java.io.FileReader: true
ClassLoader.findLoadedClass()可用于确认一个类与initiating loader关系。
引用
findLoadedClass
protected final Class<?> findLoadedClass(String name)
Returns the class with the given binary name if this loader has been recorded by the Java virtual machine as an initiating loader of a class with that binary name. Otherwise null is returned.
Parameters:
name - The binary name of the class
Returns:
The Class object, or null if the class has not been loaded
Since:
1.1
读书要谨慎,切记不要人云亦云。