JVM类加载器
一、类加载机制
(1)什么情况会触发类加载?
1.类的静态属性被访问
2.类的静态方法被调用
3.使用类实例化对象
4.子类被用到时
5.反射、注解
(2)类加载器的分类
- 启动类加载器(Bootstrap Class Loader)是优先级最高的加载器,最先进行加载。负责加载JDK目录/jre/lib 中相关jar包。包含了所有核心类,例如:String、System等。
- 扩展类加载器(Extension Class Loader):负责加载扩展类。具体就是JDK目录/jre/lib/ext。
- 应用程序加载器(Application Class Loader)负责加载类路径中字节码文件。也就是平时我们所说的classpath中内容
(3) 类的生命周期
-
加载(Loading)
-
链接(Linking)
-
校验(verify):校验加载的字节码文件是否正确。
-
准备(prepare):所有静态变量初始化并赋予默认值。
-
解析(resolve) : 把符号引用转换为直接引用。
-
-
初始化(Initialization):执行静态代码块和静态变量赋值。
-
运行。运行字节码文件。
-
卸载。运行结束后进行卸载。
二、类加载器源码分析
(1)Launcher类介绍:sun.misc.Launcher 是JVM的入口类。
比较重要的就是启动类加载器加载的路径和ClassLoader类对象。
(2)ClassLoader介绍
ClassLoader是Java中提供的类加载器父类。所有的类加载器都是这个类的子类或子孙类。
提供了全局属性parent,这意味着类加载器之间具有逻辑父子关系(不是继承关系)
(3)获取类加载器
可以通过:类名.class.getClassLoader()进行查看类是由哪种加载器进行加载。getClassLoader()返回值为ClassLoader类对象。
其中:类.class 表示获取字节码文件对象。类.class.getClassLoader()表示由哪个加载器对象加载这个字节码文件。
(4)获取父加载器
ClassLoader中包含getParent()方法,表示获取当前加载器的父加载器。
package com.java.test;
public class Test08 {
public static void main(String[] args) {
ClassLoader classLoader = Stu.class.getClassLoader();
System.out.println(classLoader);//jdk.internal.loader.ClassLoaders$AppClassLoader@2437c6dc
ClassLoader parent = classLoader.getParent();
System.out.println(parent);//jdk.internal.loader.ClassLoaders$PlatformClassLoader@48140564
ClassLoader parent1 = parent.getParent();
System.out.println(parent1);//null
}
}
(5)为什么ExtClassLoader的父加载器是null
在Launcher中并没有BootstrapClassLoader类。因为Java中并没有提供BootstrapClassLoader类,而是通过C/C++语言编写的。既然Java中没有这个类所以我们在获取ExtClassLoader的父加载器时自然为null。
(6)类加载的父子关系应该是下面的父子关系
(7)全盘负责委托机制
这是类加载的一种机制。即:当一个ClassLoader加载一个类时,除非明确指定,否则这个类所依赖和引用的类也由这个ClassLoader进行加载。
(8)双亲委派机制
双亲委派机制在代码中体现可以通过java.lang.ClassLoader中的loadClass()方法进行查看。
1. 委派的过程就是一层一层向上找的过程。只要当前加载器加载过,就不会重新加载。如果没有加载过,会向上寻找是否加载过。
2. 当加载到Bootstrap ClassLoader后会一层一层的向下判断是否可以进行加载,如果能加载则加载。如果不能加载向下一层寻找下个加载器是否能加载。如果到最后一层都无法加载则报ClassNotFoundException。
优点:避免重复加载(加载一次就不加载)和避免核心类的串改(优先Bootstrap classloader)