ClassLoader学习笔记

1.   一些基本的 ClassLoader

 

Java 中基本的 ClassLoader 3 个: BootStrapClassLoader ExtClassLoader AppClassLoader

  • BootStrapClassLoader: 用于加载 <JAVA_HOME>/lib 下的类。
  • ExtClassLoader: 用于加载 <JAVA_HOME>/lib/ext 下的类。
  • AppClassLoader: 用于加载当前应用程序中用到的类。

应用程序启动后,先由 BootStrapClassLoader 加载 <JAVA_HOME>/lib 下基本的 jar ,然后由 ExtClassLoader 加载 <JAVA_HOME>/lib/ext 下的 jar ,最后由 AppClassLoader 加载 CLASSPATH 目录下定义的类。

 

2.   类的加载 / 查找过程 使用 parent 委托模式

当需要加载一个新类型 A 的时候:

  • 当前 ClassLoader 查找 A 是否已加载,如果已加载则直接返回。
  • 如果 ClassLoader parent 不为空,则使用 parent 去加载 / 查找该类型。
  • 如果 parent 为空或 parent 加载失败,则使用 BootStrapClassLoader 去查找该类型是否已加载。
  • 如果仍然加载不成功,才使用自己去加载该类。
  • 如果还不成功,则抛出 ClassNotFoundException

使用 parent 委托模式的好处是:可以避免重复加载;可以保证核心类型(如 java.lang.String )不被用户定义覆盖。

 

3.   编写自己的 ClassLoader

  • 直接继承抽象类 ClassLoader
  • 覆盖方法 protected Class<?> findClass(String name) throws ClassNotFoundException ,一般的流程为:从资源中读取类定义到字节数组中,然后调用父类中的方法 defineClass() 来从字节数组获取 Class 对象,最后直接返回 Class 对象。
    public class MyClassLoader extends ClassLoader {
    
      protected Class<?> findClass(String name) throws ClassNotFoundException {
    	byte[] bytes = this.loadClassBytes(name);
    	Class<?> c = super.defineClass(name, bytes, 0, bytes.length);
    	if (c == null)
    		throw new ClassNotFoundException("class definition is null");
    	return c;
      }
    
      private byte[] loadClassBytes(String name) {
         ... ... ... ...
      }
    
    } 

4.  一点体会

不同的 ClassLoader 如果没有 parent-child 关系,则它们的 context 是相互独立的。同一个类在不同的 ClassLoader 中被看成是不同的且毫无关系的两个类型。

例如,执行下面的代码段,会发现输出均为false。

public void testLoadClassWithDifferentClassLoader() throws Exception {
	URL url = new URL("file:d:/temp/");
	URLClassLoader cl1 = new URLClassLoader(new URL[] { url });
	URLClassLoader cl2 = new URLClassLoader(new URL[] { url });
	Class<?> c1 = cl1.loadClass("Sample1");
	Class<?> c2 = cl2.loadClass("Sample1");
	System.out.println("c1==c2? " + (c1 == c2));
	System.out.println("c1.equals(c2)? " + c1.equals(c2));
}
 

 

你可能感兴趣的:(java,C++,c,ext,C#)