一、类加载的时机
- 类从被加载到虚拟机内存中开始,到 卸载出内存为止,它的整个生命周期包括了:加载、验证、准备、解析、初始化、使用和卸载七个阶段。其中验证、准备和解析三个部分统称为连接。
二、类加载器
- 定义:虚拟机设计团队把类加载阶段中的”通过一个类的全限定名来获取描述此类的二进制字节流“这个动作放到Java虚拟机外部去实现,以便让应用程序自己决定如何去获取所需要的类。实现这个动作的代码模块被称为”类加载器“。
- 比较两个类是否“相等”,只有在这两个类是否是由同一个类加载器加载的前提之下才有意义,否则,即使这两个类是来源于同一个Class文件,只要加载它们的类加载器不同,那这两个类就必定不相等。
三、双亲委派模型
- 站在Java虚拟机的角度来讲,只存在两种不同的类加载器:一种是启动类加载器(Bootstrap ClassLoader),这个类加载器使用C++语言实现,是虚拟机自身的一部分;另外一种就是所有其他的类加载器,这些类加载器都有java语言实现,独立于虚拟机外部,并且全都集成自抽象类java.lang.ClassLoader。
- 启动类加载器(Bootstrap ClassLoader):负责将存放在<JAVA_HOME>\lib目录中的,或者被-Xbootclasspath参数所指定的路径中的,并且是虚拟机识别的(仅按照文件名识别,名字不符合的类库即使放在lib目录中也不会被加载)类库加载到虚拟机内存中。该加载器无法被Java程序直接引用。
- 扩展类加载器(Extension ClassLoader):由sun.misc.Launcher$ExtClassLoader实现,它负责加载<JAVA_HOME>\lib\ext目录中的,或者被java.ext.dirs系统变量所自定的路径中的所有类库,开发者可以直接使用扩展类加载器。
- 应用程序类加载器(Application ClassLoader):由sun.misc.Launcher$AppClassLoader来实现。由于这个类加载器是ClassLoader中的getSystemClassLoader()方法的返回值,所以一般也称它为系统类加载器。它负责加载用户类路径上(ClassPath)所指定的类库。如果应用程序中没有自定义的类加载器,则应用程序类加载器就是程序默认的类加载器。
- 类加载器之间的父子关系是通过组合关系来实现的,即子类使用组合关系来复用父类加载器的代码。
- 工作过程:如果一个类加载器收到了类加载请求,它首先不会自己去尝试加载这个类,而是把这个请求委派给父类加载器去完成,每一层都这样。只有当父类加载器无法完成时,子类加载器才会尝试自己去加载。
四、破坏双亲委派模型
- JDK1.2时为了要兼容之前的版本,是通过重载loadClass()方法来实现类加载器的,但是现在只需要重写findClass()方法即可。
- 当基础类要调用回用户的代码,例如JNDI,Java设计团队设计了线程上下文加载器。
- 由于用户对程序动态性的追求而导致的,例如代码热替换,模块热部署,此时的类加载器是网状结构的,出现了同级查找的现象。