- 获取到ClassLoader后调用loadClass(“A”)方法加载运行的类A
- 加载完成执行A类的main方法
- 程序运行结束
- JVM销毁
loadClass的类加载过程
===================
===================================================================================================================================================================================================
加载 ----> 验证 ----> 准备 ----> 解析 ----> 初始化 ----> 使用 ----> 卸载
谈及比较多的是前五个
- **加载:**我们说jvm执行的java字节码,编译后在磁盘上,总得读取这个字节码文件吧 ,通过啥读 IO呗 , 所以第一步肯定是加载字节码文件。
- 验证:JVM总不能说读到啥就直接运行了吧,你外面有个A.class 里面是一堆JVM规范不认识的内容,也执行不了啊 。 符合JVM规范才能执行后续的步骤,所以第二步是 校验字节码文件的正确性。
- 准备:给类的静态变量分配内存,并赋予默认值。 我们的类里,可能会包含一些静态变量吧 。 比如
public static final int a = 12;
得给a分配个默认值 0 ,再比如public static User user = new User();
给 static的变量 User分配内存,并赋默认值null (final修饰的常量,直接赋值)。 - 解析:这个地方不是很好理解, 解析是什么意思呢?将符号引用替换为直接引用。 符号引用 ? 直接引用? what ? 我们的类的静态方法,比如main方法,其实在Java中有个叫法 都是叫符号 。 这个阶段就会吧,一些静态方法(符号引用,比如刚才说的main方法)替换为指向数据所存内存的指针或者句柄等(直接引用)【找到具体在内存中的位置】。 这个就是静态链接过程(在类加载期间完成)。 动态链接是在程序运行期间完成的将符号引用替换为直接引用 (比如某个普通方法的调用)。
- 初始化:上面的步骤完事儿以后,这一步主要是对类的静态变量初始化为指定的值,执行静态代码块。 比如刚才第二步的
public static final int a = 12;
,第二步给static变量赋了默认值,这一步就该把12赋值给它了。 还有 static的 Userpublic static User user = new User();
实例化User。
说明:主类在运行过程中如果使用到其它类,会逐步加载这些类。jar包或war包里的类不是一次性全部加载的,是使用到时才加载。
类加载顺序示例:
============ public class TestDynamicLoad { static { System.out.println(“加载TestDynamicLoad类中的静态代码块”); } public static void main(String[] args) { new A(); System.out.println(“执行main方法中的代码”); B b = null;//B不会加载,除非这里执行 new B() } } class A{ static { System.out.println(“加载A类中的静态代码块”); } public A(){ System.out.println(“加载A类中的构造方法”); } } class B{ static { System.out.println(“加载B类中的静态代码块”); } public B(){ System.out.println(“加载B类中的构造方法”); } }
执行结果:
加载TestDynamicLoad类中的静态代码块
加载A类中的静态代码块
加载A类中的构造方法
执行main方法中的代码
类加载器
========
- 引导类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的核心类库,比如rt.jar、charsets.jar等
- 扩展类加载器:负责加载支撑JVM运行的位于JRE的lib目录下的ext扩展目录中的JAR类包
- 应用程序类加载器:负责加载ClassPath路径下的类包,主要就是加载我们应用中自己写的那些类
- 自定义加载器:负责加载用户自定义路径下的类包
类加载器示例:
import com.sun.crypto.provider.DESKeyFactory; import sun.misc.Launcher; import java.net.URL; public class TestJDKClassLoader { public static void main(String[] args) { System.out.println(String.class.getClassLoader()); System.out.println(DESKeyFactory.class.getClassLoader().getClass().getName()); System.out.println(TestJDKClassLoader.class.getClassLoader().getClass().getName()); System.out.println(); ClassLoader appClassLoader = ClassLoader.getSystemClassLoader(); ClassLoader extClassloader = appClassLoader.getParent(); ClassLoader bootstrapLoader = extClassloader.getParent(); System.out.println("the bootstrapLoader : " + bootstrapLoader); System.out.println("the extClassloader : " + extClassloader); System.out.println("the appClassLoader : " + appClassLoader); System.out.println(“AppClassLoader的父类加载器为ExtClassLoader,ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader没有父类加载器,而是 BootstrapClassLoader”); System.out.println(); System.out.println(“JRE的lib目录下的核心类库,bootstrapLoader加载以下文件:”); URL[] urls = Launcher.getBootstrapClassPath().getURLs(); for (int i = 0; i < urls.length; i++) { System.out.println(urls[i]); } System.out.println(); System.out.println(“JRE的lib目录下的ext扩展目录中的JAR类包,extClassloader加载以下文件:”); String[] extClassloaderStr = System.getProperty(“java.ext.dirs”).split(“;”); for (String s : extClassloaderStr) { System.out.println(s); } System.out.println(); System.out.println(“加载ClassPath路径下的类包,appClassLoader加载以下文件:”); String[] split = System.getProperty(“java.class.path”).split(“;”); for (String s : split) { System.out.println(s); } } } 执行结果: null sun.misc.Launcher$ExtClassLoader sun.misc.Launcher$AppClassLoader the bootstrapLoader : null the extClassloader : sun.misc.Launcher$ExtClassLoader@3dd3bcd the appClassLoader : sun.misc.Launcher$AppClassLoader@14dad5dc AppClassLoader的父类加载器为ExtClassLoader,ExtClassLoader的父类加载器为null,null并不代表ExtClassLoader没有父类加载器,而是 BootstrapClassLoader JRE的lib目录下的核心类库,bootstrapLoader加载以下文件: file:/D:/Environment/JDK/lib/resources.jar file:/D:/Environment/JDK/lib/rt.jar file:/D:/Environment/JDK/lib/sunrsasign.jar file:/D:/Environment/JDK/lib/jsse.jar file:/D:/Environment/JDK/lib/jce.jar file:/D:/Environment/JDK/lib/charsets.jar file:/D:/Environment/JDK/lib/jfr.jar file:/D:/Environment/JDK/classes JRE的lib目录下的ext扩展目录中的JAR类包,extClassloader加载以下文件: D:\Environment\JDK\lib\ext C:\Windows\Sun\Java\lib\ext 加载ClassPath路径下的类包,appClassLoader加载以下文件: D:\Environment\JDK\jre\lib\charsets.jar D:\Environment\JDK\jre\lib\deploy.jar D:\Environment\JDK\jre\lib\ext\access-bridge-64.jar D:\Environment\JDK\jre\lib\ext\cldrdata.jar D:\Environment\JDK\jre\lib\ext\dnsns.jar D:\Environment\JDK\jre\lib\ext\jaccess.jar D:\Environment\JDK\jre\lib\ext\jfxrt.jar D:\Environment\JDK\jre\lib\ext\localedata.jar D:\Environment\JDK\jre\lib\ext\nashorn.jar D:\Environment\JDK\jre\lib\ext\sunec.jar D:\Environment\JDK\jre\lib\ext\sunjce_provider.jar D:\Environment\JDK\jre\lib\ext\sunmscapi.jar D:\Environment\JDK\jre\lib\ext\sunpkcs11.jar D:\Environment\JDK\jre\lib\ext\zipfs.jar D:\Environment\JDK\jre\lib\javaws.jar D:\Environment\JDK\jre\lib\jce.jar D:\Environment\JDK\jre\lib\jfr.jar D:\Environment\JDK\jre\lib\jfxswt.jar D:\Environment\JDK\jre\lib\jsse.jar D:\Environment\JDK\jre\lib\management-agent.jar D:\Environment\JDK\jre\lib\plugin.jar D:\Environment\JDK\jre\lib\resources.jar D:\Environment\JDK\jre\lib\rt.jar D:\Project\Personal\website\reception\target\classes D:\Environment\RepMaven\org\springframework\boot\spring-boot-starter\2.2.6.RELEASE\spring-boot-starter-2.2.6.RELEASE.jar D:\Environment\RepMaven\org\springframework\boot\spring-boot\2.2.6.RELEASE\spring-boot-2.2.6.RELEASE.jar