分析Java的类加载器与ClassLoader(一):概述


有关类加载器的基本知识,请先看文章:http://blog.csdn.net/tangyangguang/article/details/8878302



1,类加载器概述
        Java程序是由许多独立的类字节码文件(*.class)组成。一个应用程序可能直接或间接的涉及到成千上万个Class,如果一次性全部装入内存,无疑是时间和空间的浪费。所以JVM启动时只会加载核心的类字节码和必要的其他类字节码,用户自定义的类将会在第一次使用时加载,这叫做动态加载类字节码。而 类加载器就是用来加载类字节码文件到JVM中,以供程序使用的。

2,JVM中的自带的类加载器
  • Bootstrap ClassLoader
    • 启动类加载器,用c/c++实现的,它负责加载核心Class(即所有java.*开头的类)。
    • 这个类加载器没有对应的Java类。
  • Extension ClassLoader
    • 扩展类加载器,它负责加载扩展的Class(存放在JRE的lib/ext/目录下的类)。
    • 这个类加载器对应sun.misc.Launcher$AppClassLoader类。
  • Application ClassLoader
    • 应用程序类加载器,负责加载应用程序自身的类(CLASSPATH目录中的Class)。
    • 这个类加载器对应sun.misc.Launcher$ExtClassLoader类。

Bootstrap ClassLoader是最顶级的类加载器,也是Extension ClassLoader的父“类加载器”,Extension ClassLoader是Application ClassLoader的父“类加载器”。如下图所示:

    


测试代码:
package cn.itcast;

public class ClassLoaderTest {

	public static void main(String[] args) {
		ClassLoader cl = Thread.currentThread().getContextClassLoader();
		System.out.println("当前的类加载器:" + cl);
		while(cl != null){
			cl = cl.getParent();
			System.out.println("parent类加载器:" + cl);
		}
	}
}

执行结果:

当前的类加载器:sun.misc.Launcher$AppClassLoader@19821f
parent类加载器:sun.misc.Launcher$ExtClassLoader@addbf1
parent类加载器:nul


3,“ClassLoader”与“类加载器”的区别
        我们平常说的ClassLoader实际上表示两个概念:一是“类加载器”概念;二是ClassLoader类,全名是java.lang.ClassLoader。java.lang.ClassLoader是JDK中的一个普通类(ClassLoader是一个抽象类),是用Java语言编写的, 我们可以自己写一个ClassLoader的子类,以扩展Java虚拟机加载类的方式。 


4,类加载器使用委托模式进行类加载
        类加载器使用委托模型来搜索类和资源。每个“类加载器”实例都有一个相关的父“类加载器”(parent)。 需要查找类或资源时,类加载器实例会先委托给其父类加载器进行加载,如果parent是null的话,则表示为Bootstrap类加载器,只有在上级类加载器没有找到的情况下,自己才会加载,这就避免我们重写一些系统类,来破坏系统的安全。

分析java.lang.ClassLoader的源码:
protected synchronized Class loadClass(String name, boolean resolve) throws ClassNotFoundException {
	// 先从缓存中拿Class:
	// 1, 如果这个Class之前被加载过,就会记录到缓存中,这里就会返回缓存的Class对象。
	// 2, 如果这个Class之前没有被加载过,则这里返回null
	Class c = findLoadedClass(name);
	if (c == null) {
		// 如果缓存中没有想要的Class对象,则进行加载
		try {
			// 如果parent不为null,则调用parent的loadClass进行加载
			if (parent != null) {
				c = parent.loadClass(name, false);
			}
			// 如果parent为null,则调用BootstrapClassLoader进行加载
			else {
				c = findBootstrapClass0(name);
			}
		} catch (ClassNotFoundException e) {
			// 如果仍然无法加载成功,则调用自身的findClass进行加载
			c = findClass(name);
		}
	}
	if (resolve) {
		resolveClass(c);
	}
	return c;
}

从以上源码中可以得知:
1,类加载器使用委托模式进行类加载。
2,我们如果想自己写一个类加载器,则只需要重载findClass()这个方法。


5,规则细节

  1. 类加载器使用委托模式进行类加载。
  2. Class.getClassLoader()方法可以返回加载这个Class的ClassLoader,如果返回null,表示是Bootstrap ClassLoader。
  3. 如果类A引用了类B,不管是直接引用还是用Class.forName()引用,JVM就会找到加载类A的ClassLoader,并用这个ClassLoader来加载类B。
  1. 我们如果想自己写一个类加载器,则只需要重载findClass()这个方法。
  2. 在自定义的ClassLoader对象中,需要指定一个父对象;如果没有指定的话,系统自动指定ClassLoader.getSystemClassLoader()为父对象。
  3. 我们可以在自定义的ClassLoader中重写loadClass()方法,在实现代码中不采用委托模式进行类加载,但不推荐这样做。
  1. Class.forName()是加载类字节码并进行初始化(例如执行static代码块),如果之前加载过,则会使用缓存的Class。
  2. ClassLoader.loadClass()是加载类字节码,但不会进行初始化(例如不会执行static代码块),而是在第一次使用这个类时执行初始化。
  3. 如果使用同一个ClassLoader实例多次加载同一个Class(自己重写loadClass()方法可以实现这个效果),会抛java.lang.LinkageError错误。

        (实验代码将写到后面的文章中)



评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值