首先看一下类装载器的工作机制
定义一:类装载器是寻找类的字节码文件并构造出类在JVM内部表示对象的组件。
在java中,类装载器将一个类装载到JVM中,要经过的步骤如下:
1.装载:查找和导入Class文件
2.链接:
执行校验、准备和解析步骤。其中解析步骤是可以选择的。
1)校验:检查载入的class文件的正确性;
2)准备:给类的静态变量分配存储空间。
3)解析:将符号引用转换成直接引用。
3.初始化:对类的静态变量、静态代码块执行初始化工作。
类装载器工作由ClassLoader以及其子类负责,ClassLoader是一个重要的Java运行时系统组件,它负责在运行时查找和装入Class字节码文件。
Jvm在运行时会产生三个ClassLoader;根装载器、ExtClassLoader和AppClassLoader。其中根装载器不是ClassLoader的子类,因为它使用的是C++编写。
根装载器负责装载JRE的核心类库,如:JRE目标下的rt.jar等jar包。
ExtClassLoader和ApplClassLoader都是ClassLoader的子类,ClassLoader是一个抽象类,位于java.lang包下。ExtClassLoader和AppClassLoader负责的方向不一样。
ExtClassLoader负责装载JRE扩展目录下的Jar包,然而AppClassLoader负责装载Classpath下的类包,也就是我们引用的外部jar包,比如mysql的数据库jar包。
其中根装载器是ExtClassLoader的父装载器,ExtClassLoader是AppClassLoader的父装载器,一般情况下,所有的装载活动都是用AppClassLoader装载。
public class ClassLoaderTest {
public static void main(String args[]){
ClassLoader loader=Thread.currentThread().getContextClassLoader();
System.out.println("当前运行装载器是:"+loader);
System.out.println("父装载器是:"+loader.getParent());
System.out.println("父亲的父亲装载器是:"+loader.getParent().getParent());
}
}
运行结果是:
当前运行装载器是:sun.misc.Launcher$AppClassLoader@1a46e30
父装载器是:sun.misc.Launcher$ExtClassLoader@3e25a5
父亲的父亲装载器是:null
我们可以看到,最后的父亲是没有的,因为那个是C++编写的,我们没有办法获得他的句柄。
JVM装载类时使用的全盘负责委托机制,
全盘负责的意思是:当一个ClassLoader装载一个类的时候,除非显示的使用另外一个ClassLoader,该类所依赖以及引用的类也由这个ClassLoader装载。
委托机制是指:
先委托父装载器寻找目标类,只有在找不到的情况下,才在自己的类路径下寻找并装载目标类。
二:ClassLoader相关重要方法
1.Class loadClass(String name)
name参数指定类装载器需要装载的类的名字,必须使用全限定名,如:com.zhuzhu.Test。该方法有一个重载方法loadClass(String name,boolean resolve),resolve参数告诉装载器是否要解析此类,在初始化前要考虑类的解析工作,但并不是所有的类都需要解析,如果JVM只需要知道该类是否存在或者找出其父类等等,比如File一样,就可以将resolve设置为false;
2.Class defineClass(String name,byte[] b,int off,int len)
此方法将类文件的字节数组转换为JVM内部的java.lang.Class对象。字节数组可以从本地文件系统,远程网络获取。name为字节数组对应的全限定类名。
3.Class findSystemClass(Stirng name)
从本地文件系统载入Class文件,如果本地系统不存在Class文件,将抛出ClassNotFondException异常。
4.ClassLoader getParent();
得到父装载器。
除了JVM默认的是哪个ClassLoader以外,可以编写自己的第三方类装载器,以实现一些特殊的需求。类文件被装载解析后,在JVM内将拥有一个对应的java.lang.Class类描述该对象,该类的实例都拥有指向这个类描述对象的引用,而类描述对象又拥有指向关联ClassLoader的引用。
每一个类在JVM中都拥有一个对应的java.lang.Class对象,他们提供类结构的信息描述。