理解java类加载机制

一、java加载器介绍
java中有三类预定义加载器分别是 AppClassLoader、ExtClassLoader、BootstrapClassLoader,其中,前2个加载器是java实现的通过继承 URLClassLoader实现,在 sun.misc.Launcher [/color]类中可以看到源码,而BootstrapClassLoader[color=blue]为本地代码实现,java采用的是父委托机制来加载类。
二、父委托机制介绍
假设系统加载器 AppClassLoader需要加载类A,那么,系统加载器会先委托其父加载器去加载,同样父加载器也会委托给其父加载器,一层一层往上委托直到父加载器为null,这时会调用 BootstrapClassLoader去加载,如果加载失败,则从上往下一个个加载器去加载,如果到 AppClassLoader加载时还未加载成功,则抛出 ClassNotFoundException

具体的加载过程可以看 ClassLoader类的 loadClass方法:、
protected synchronized Class<?> loadClass(String name, boolean resolve)
            throws ClassNotFoundException {
        // 首先判断该类型是否已经被加载
        Class c = findLoadedClass(name);
        if (c == null) {
            //如果没有被加载,就委托给父类加载或者委派给启动类加载器加载
            try {
                if (parent != null) {
                    //如果存在父类加载器,就委派给父类加载器加载
                    c = parent.loadClass(name, false);
                } else {
                    //如果不存在父类加载器,就检查是否是由启动类加载器加载的类,通过调用本地方法native Class findBootstrapClass(String name)
                    c = findBootstrapClass0(name);
                }
            } catch (ClassNotFoundException e) {
              // 如果父类加载器和启动类加载器都不能完成加载任务,才调用自身的加载功能 
               c = findClass(name);
            }
        }

        if (resolve) {
            resolveClass(c);
        }
        return c;
    }

三、三类加载器的加载路径分析
通过下面的代码打印出加载器的加载路径:
import java.net.URL;
import java.net.URLClassLoader;

public class AnalyzeClassLoaderPath {
    public static void main(String[] args) {
	System.out.println("BootstrapClassLoader 的加载路径:");
	URL[] urls = sun.misc.Launcher.getBootstrapClassPath().getURLs();

	for (URL url : urls) {
	    System.out.println(url);
	}
	System.out.println("--------------------------------------");
	
	URLClassLoader extClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader().getParent();
	System.out.println(extClassLoader);
	System.out.println("扩展类加载器 的加载路径:");
	urls = extClassLoader.getURLs();

	for (URL url : urls) {
	    System.out.println(url);
	}
	System.out.println("--------------------------------------");
	
	// 获取appclassloader
	URLClassLoader appClassLoader = (URLClassLoader) ClassLoader.getSystemClassLoader();
	System.out.println(appClassLoader);
	System.out.println("App类加载器 的加载路径:");
	urls = appClassLoader.getURLs();

	for (URL url : urls) {
	    System.out.println(url);
	}
	System.out.println("--------------------------------------");
    }
}

输出结果如下:
BootstrapClassLoader 的加载路径:
file:/E:/jdk1.6.0_06/jre/lib/resources.jar
file:/E:/jdk1.6.0_06/jre/lib/rt.jar
file:/E:/jdk1.6.0_06/jre/lib/sunrsasign.jar
file:/E:/jdk1.6.0_06/jre/lib/jsse.jar
file:/E:/jdk1.6.0_06/jre/lib/jce.jar
file:/E:/jdk1.6.0_06/jre/lib/charsets.jar
file:/E:/jdk1.6.0_06/jre/classes
--------------------------------------
sun.misc.Launcher$ExtClassLoader@6b97fd
扩展类加载器 的加载路径:
file:/E:/jdk1.6.0_06/jre/lib/ext/dnsns.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/localedata.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/sunjce_provider.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/sunmscapi.jar
file:/E:/jdk1.6.0_06/jre/lib/ext/sunpkcs11.jar
--------------------------------------
sun.misc.Launcher$AppClassLoader@192d342
App类加载器 的加载路径:
file:/E:/workspace/dreams/target/classes/
--------------------------------------

我们也可以将自己写的java类放到上面的路径中,交由不同的加载器进行加载, 经过试验发现在jre/classes下放入class文件可以加载,但在jre/lib目录下的jar包中加入class文件或加入jar包都不能加载,而在jre/lib/ext目录下加入jar包可以加载但class文件不行。

你可能感兴趣的:(java)