2020-02-04
程序在启动的时候,并不会一次性加载程序所要用的所有class文件,而是根据程序的需要,通过Java的类加载机制(ClassLoader)来动态加载某个 class 文件到内存当中的,从而只有 class 文件被载入到了内存之后,才能被其它 class 所引用。所以 ClassLoader 就是用来动态加载 class 文件到内存当中用的。
结构
![](https://img.haomeiwen.com/i1534809/a86024b8aa19bacd.png)
1.BootStrapClassLoader(引导类加载器) 处于类加载器层次结构的最高层,负责 sun.boot.class.path 路径下类的加载,默认为 jre/lib 目录下的核心 API 或 -Xbootclasspath 选项指定的 jar 包。
2.ExtClassLoader (扩展类加载器)的加载路径为 java.ext.dirs,默认为 jre/lib/ext 目录或者 -Djava.ext.dirs 指定目录下的 jar 包加载。
3.AppClassLoader(系统类加载器) 的加载路径为 java.class.path,默认为环境变量 CLASSPATH 中设定的值。也可以通过 -classpath 选型进行指定。
4.用户自定义 ClassLoader 可以根据用户的需要定制自己的类加载过程,在运行期进行指定类的动态实时加载。
类装载方式
1.隐式装载,程序在运行过程中当碰到通过new 等方式生成对象时,隐式调用类装载器加载对应的类到jvm中。
2.显式装载,通过class.forname(),this.getClassLoader().loadClass()等方法,显式加载需要的类。
重复加载
对于同一个类加载器实例来说,名字相同的类只能存在一个,并且仅加载一次。不管该类有没有变化,下次再需要加载时,它只是从自己的缓存中直接返回已经加载过的类引用。
所以重复加载可能会导致类没有被及时更新
双亲委派
当一个ClassLoader实例需要加载某个类时,它会试图亲自搜索某个类之前,先把这个任务委托给它的父类加载器,这个过程是由上至下依次检查的,首先由最顶层的类加载器Bootstrap ClassLoader试图加载,如果没加载到,则把任务转交给Extension ClassLoader试图加载,如果也没加载到,则转交给App ClassLoader 进行加载,如果它也没有加载得到的话,则返回给委托的发起者,由它到指定的文件系统或网络等URL中加载该类。
JVM在判定两个class是否相同时,不仅要判断两个类名是否相同,而且要判断是否由同一个类加载器实例加载的。只有两者同时满足的情况下,JVM才认为这两个class是相同的。就算两个class是同一份class字节码,如果被两个不同的ClassLoader实例所加载,JVM也会认为它们是两个不同class。
线程
每个运行中的线程都有一个成员ContextClassLoader,用来在运行时动态地载入其它类
定义自已的类加载器
分为两步:
1、继承java.lang.ClassLoader
2、重写父类的findClass方法
文件类加载器,加载存储在文件系统上的 Java 字节代码。
网络类加载器,Java 字节代码(.class)文件存放在服务器上,客户端通过网络的方式获取字节代码并执行。当有版本更新的时候,只需要替换掉服务器上保存的文件即可。通过类加载器可以比较简单的实现这种需求。
网友评论