谁是initiating loader

《深入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


读书要谨慎,切记不要人云亦云。

你可能感兴趣的:(Java综合)