谁是initiating loader

本文揭示并修正了《深入Java虚拟机》第二版中关于类加载器使用的一个常见误解,通过具体代码实例和ClassLoader.findLoadedClass()方法验证了实际加载过程与书中描述不符的情况。强调了阅读技术书籍时需审慎思考的重要性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

《深入Java虚拟机》第二版(很老的那本,Bill Venners写的,有中文翻译那本)第八章讲解类加载器用了个[url=http://www.artima.com/insidejvm/ed2/linkmod3.html]Cindy、Mom、Grandma的例子[/url]。但那个例子是错的。[url=http://mail.openjdk.java.net/pipermail/jdk6-dev/2011-October/002532.html]发了邮件到jdk6-dev邮件列表[/url],等待答复。顺便发这边大家讨论。

那个例子说,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。但事实却不是如此。

代码例子:
[code]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;
}
}[/code]
Dummy.java
[code]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();
}
}
}[/code]

运行结果:
[code]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[/code]

ClassLoader.findLoadedClass()可用于确认一个类与initiating loader关系。
[quote]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
[/quote]

读书要谨慎,切记不要人云亦云。
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值