有些时候呢,当你对一个东西很熟悉了的时候,当你再重拾起这件东西的时候呢,你就有可能会有对其更深的理解,或者是想去更深的理解。.class文件被类加载器ClassLoader加载到内存,并被表示为Class对象,被JVM解析执行,那么,今儿,彻底来了解了解它的工作机制。
类装载器ClassLoader呢,就是寻找类或接口字节码文件(.class)进行解析并构造JVM内部对象表示的组件。类加载的工作由ClassLoader及其子类负责,它并非是一次性的加载多个class文件,需要的时候才才加载进来,这个就是我们常说的运行期间动态加载,如何想看看究竟类的具体加载过程呢,可以用-verbose:class参数,现看例子程序来了解了解ClassLoader何来个运行期动态加载,以后看看具体的加载过程,如下:
- public class DynamicLoadClassDemo {
- public static void main(String[] args) {
- new WaitingToLoadedOneClass();
- System.out.println("demonstrate dynamic loaded......");
- new WaitingToLoadedTwoClass();
- }
- }
- class WaitingToLoadedOneClass {
- }
- class WaitingToLoadedTwoClass {
- }
看这个例子,里面有三个类,主类为DynamicLoadClassDemo,在main函数里,在声明两个对象之间有一条打印语句,如果ClassLoader是动态加载类的话,那么,输出的语句会在这两个类的加载中间对吧,为了能够看清楚这一过程,我们加上-verbose:class,在MyEclipse编辑窗口中,右击-->“Run As”-->“Open Run Dialog...”-->“Arguments”-->“VM arguments”,输入-verbose:class-->“Run”,会把类的加载如实的打印在控制台上,现截我们敢兴趣的运行结果如下:
- [Loaded com.cui.hourse.reflectDemo.DynamicLoadClassDemo from file:/G:/workspace/HourseSystem/WebRoot/WEB-INF/classes/]
- [Loaded com.cui.hourse.reflectDemo.WaitingToLoadedOneClass from file:/G:/workspace/HourseSystem/WebRoot/WEB-INF/classes/]
- demonstrate dynamic loaded......
- [Loaded com.cui.hourse.reflectDemo.WaitingToLoadedTwoClass from file:/G:/workspace/HourseSystem/WebRoot/WEB-INF/classes/]
完全的动态加载呀,输出语句,就在两个声明对象之间。
实际上呢,输的语句不仅仅是这些了,JVM在运行时会产生三个ClassLoader:根装载器、扩展类装载器(ExtClassLoader)、系统应用类装载器(AppClassLoader)。
现分别对这几个类的装载器说明如下:
1)根装载器(bootstrap class Loader):计算机本地语言所编写(汇编、C/C++),加载jre最核心的类,如JRE扩展目标下的rt.jar、charsets.jar...,如java.lang.String类;
2)扩展类装载器(extesion class loader):加载jre/lib/ext包里的jar类,如;
3)系统应用类装载器(applicatioin class loader):负责加载classpath路径下的包类,通常是用户定义的类,也是系统默认的装载方式;
JVM装载类时使用“全盘负责委托机制”。“全盘负责”是指当一个ClassLoader装载一个类时,该类所依赖及引用的类也由这个ClassLoader载入,当然了,别指定一ClassLoader除外;“委托机制”是指呢委托父装载器寻找目标类,只有找不到的情况下,才会从自己的当前路径下查找并装载目标类。就像AppClassLoader-->ExtClassLoader-->根装载器,这三个装载器之间存在着父子层级之间的关系,让我们来做个实验看看:
- //根加载器,因为非Java语言所写,所以会返回null
- System.out.println(String.class.getClassLoader());
- //jre6\lib\ext包下dnsns.jar里的类,扩展类加载器加载
- System.out.println(sun.net.spi.nameservice.dns.DNSNameService.class.getClassLoader());
- //系统默认加载方式,应用类加载器,然后获取它的父加载器,一级一级的往上,分别为扩展类加载器、根加载器
- System.out.println(ClassLoader.getSystemClassLoader());
- System.out.println(ClassLoader.getSystemClassLoader().getParent());
- System.out.println(ClassLoader.getSystemClassLoader().getParent().getParent());
控制台输出如下信息:
- null
- sun.misc.Launcher$ExtClassLoader@addbf1
- sun.misc.Launcher$AppClassLoader@19821f
- sun.misc.Launcher$ExtClassLoader@addbf1
- null
完全与我们想像的一致,这样,你就理解了,呵呵!