关闭

classloader 简单介绍

316人阅读 评论(0) 收藏 举报

文章摘抄至http://longdick.iteye.com/blog/442213/

 

要深入了解ClassLoader,首先就要知道ClassLoader是用来干什么的,顾名思义,它就是用来加载Class文件到JVM,以供程序使用的。我们知道,java程序可以动态加载类定义,而这个动态加载的机制就是通过ClassLoader来实现的,所以可想而知ClassLoader的重要性如何。 

 

看到这里,可能有的朋友会想到一个问题,那就是既然ClassLoader是用来加载类到JVM中的,那么ClassLoader又是如何被加载呢?难道它不是java的类? 

 

没有错,在这里确实有一个ClassLoader不是用java语言所编写的,而是JVM实现的一部分,这个ClassLoader就是bootstrap classloader(启动类加载器),这个ClassLoader在JVM运行的时候加载java核心的API以满足java程序最基本的需求,其中就包括用户定义的ClassLoader,这里所谓的用户定义是指通过java程序实现的ClassLoader,一个是ExtClassLoader,这个ClassLoader是用来加载java的扩展API的,也就是/lib/ext中的类,一个是AppClassLoader,这个ClassLoader是用来加载用户机器上CLASSPATH设置目录中的Class的,通常在没有指定ClassLoader的情况下,程序员自定义的类就由该ClassLoader进行加载。 


 

当运行一个程序的时候,JVM启动,运行bootstrap classloader,该ClassLoader加载java核心API(ExtClassLoader和AppClassLoader也在此时被加载),然后调用ExtClassLoader加载扩展API,最后AppClassLoader加载CLASSPATH目录下定义的Class,这就是一个程序最基本的加载流程

 

java应用环境中不同的class分别由不同的ClassLoader负责加载。
一个jvm中默认的classloader有Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader,分别各司其职:

  • Bootstrap ClassLoader      负责加载java基础类,主要是 %JRE_HOME/lib/ 目录下的rt.jar、resources.jar、charsets.jar和class等
  • Extension ClassLoader       负责加载java扩展类,主要是 %JRE_HOME/lib/ext 目录下的jar和class
  • App ClassLoader           负责加载当前java应用的classpath中的所有类。

其中Bootstrap ClassLoader是JVM级别的,由C++撰写;Extension ClassLoader、App ClassLoader都是java类,都继承自URLClassLoader超类。
Bootstrap ClassLoader由JVM启动,然后初始化sun.misc.Launcher ,sun.misc.Launcher初始化Extension ClassLoader、App ClassLoader。

下图是ClassLoader的加载类流程图,以加载一个类的过程类示例说明整个ClassLoader的过程。

public class ClassLoaderTree {
	public static void main(String[] args) {
		ClassLoader loader = ClassLoaderTree.class.getClassLoader();
		/**
		 sun.misc.Launcher$AppClassLoader@39ab89 系统类加载器
		 sun.misc.Launcher$ExtClassLoader@2cb49d 扩展类加载器
		 */
		while(loader != null){
			System.out.println(loader.toString());
			loader = loader.getParent();
		}
	}
}

 

Bootstrap ClassLoader、Extension ClassLoader、App ClassLoader三者的关系如下:

Bootstrap ClassLoader是Extension ClassLoader的parent,Extension ClassLoader是App ClassLoader的parent。但是这并不是继承关系,只是语义上的定义,基本上,每一个ClassLoader实现,都有一个Parent ClassLoader。

 

可以通过ClassLoader的getParent方法得到当前ClassLoader的parent。Bootstrap ClassLoader比较特殊,因为它不是java class所以Extension ClassLoader的getParent方法返回的是NULL。

 

当使用ClassLoader类的loadClass()方法来加载某个类时,该方法只是加载该类,并不会执行该类的初始化。使用Class的forName()静态方法才会导致强制初始化该类。

package hb.reflect;
public class Tester{
	static{
		System.out.println("初始化块");
	}
}

 

package hb.reflect;
public class ClassLoaderTest {
	public static void main(String[] args) throws ClassNotFoundException {
		ClassLoader c1 = ClassLoader.getSystemClassLoader();
		//不会执行初始化
		c1.loadClass("hb.reflect.Tester");
		
		System.out.println("系统加载Tester类");
		//执行初始化内容
		Class.forName("hb.reflect.Tester");
		
	}

}

 打印内容:

系统加载Tester类

初始化块

 

如果将代码如下修改:

package hb.classloader;
public class ClassLoaderTest {

	public static void main(String[] args) throws ClassNotFoundException {
		
		ClassLoader c1 = ClassLoader.getSystemClassLoader();
		//不会执行初始化
		Class clazz = c1.loadClass("hb.classloader.Tester");
		//
		try {
			Tester tester = (Tester)clazz.newInstance();
			tester.print("class.newInstance() is ok");
		} catch (InstantiationException | IllegalAccessException e) {
			e.printStackTrace();
		}
		
		System.out.println("系统加载Tester类");
		//执行初始化内容
		Class.forName("hb.classloader.Tester");
		
	}

}

 打印结果:

初始化块

class.newInstance() is ok

系统加载Tester类

 
备注:因为在调用getInstance()方法实际上就是创建一个无参的构造函数,因此需要初始化Tester类,所以与上面的有点区别。
  • 大小: 65.9 KB
0
0

查看评论
* 以上用户言论只代表其个人观点,不代表CSDN网站的观点或立场
    个人资料
    • 访问:329063次
    • 积分:8938
    • 等级:
    • 排名:第2254名
    • 原创:1096篇
    • 转载:14篇
    • 译文:0篇
    • 评论:5条
    最新评论