类加载过程【五部曲】

加载=》验证=》准备=》解析=》初始化=》使用=》销毁

~加载:

程序的入口

~验证:

验证字节码文件,coffee bebe开头

~准备:

给静态变量分配内存,并赋初始值(int=0)

~解析:

符号引用替换为直接引用,该阶段会把一些静态方法(符号引用,比如
main()方法)替换为指向数据所存内存的指针或句柄等(直接引用),这是所谓的静态链接
程(类加载期间完成),动态链接是在程序运行期间完成的将符号引用替换为直接引用,下
节课会讲到动态链接?????

~初始化:

将类中的变量赋值为目标值,执行静态代码块

JVM(一) - 图1

jvm懒加载

类中使用导其他的类时,不会一次性全部加载,只用使用到该类时才会去加载(调用构造方法初始化时)

  1. package com.xusj.future;
  2. /**
  3. * jvm的懒加载:当类于类之间相互应用,只用当使用该类时才会使用
  4. *
  5. * @author xusj
  6. * <br>CreateDate 2022/5/23 21:39
  7. */
  8. public class Test01 {
  9. static {
  10. System.out.println("静态代码块执行");
  11. }
  12. public static void main(String[] args) {
  13. // 调用a
  14. new A();
  15. System.out.println("==========");
  16. // 这样b并不会加载,只用当调用构造方法初始化时才会被jvm加载
  17. B b = null;
  18. }
  19. }
  20. class A {
  21. static {
  22. System.out.println("a load");
  23. }
  24. public A() {
  25. System.out.println("初始化a,构造方法");
  26. }
  27. }
  28. class B {
  29. static {
  30. System.out.println("b load");
  31. }
  32. public B() {
  33. System.out.println("初始化b,构造方法");
  34. }
  35. }

双亲委派机制

谁来干

=》由四大类加载器来干的:
~引导类加载器:加载jre中java核心类库,如sun包下。。
~扩展类加载器:加载jre中ext扩展目录下的类包
~应用类加载器:加载我们自己定义的一些类
~自定义加载器:负责加载用户自定义路径下的类包(一般不会去使用)

怎么干

1、第一次进行加载的时候,jvm中所有都是空的,所以会一直委托到最顶层的引导类加载器进行加载
2、当完成第一次加载后的每一次,jvm还是自下往上进行加载,但是于第一次不同的是,在自下向上的途中,其中只要由一个加载器中有该类时直接就返回,不会继续向上委托,提高了效率
3、可以尝试看一下源码??
1)每次在调用一个类加载器的时候都会去先通过调用parent.loadClass(name, false);去判断是否有父类加载器

JVM(一) - 图2

源码解析截图(解决一些疑问)

1、
1.png
2、
2.png

为什么这么干

沙箱安全机制:
避免java核心类库中的类被篡改【可以尝试重写一下一模一样的string类】;
避免类的重复加载:
当父亲已经加载了该类,就没必要子类再加载一次了

自定义类加载器(略)

手写打破双亲委派机制(略)