关于类加载

75 阅读2分钟

IK38~9P89_0V3K1}8_ZNN{4.png

类加载是懒惰的, 首次用到时才加载(下面的初始化条件满足也会导致类加载)

    ①使用了类.class;②用类加载器的 loadClass 方法加载类

      

类初始化是懒惰的, 满足条件有

①main方法所在类

②首次访问静态方法或静态变量(非 final, 或 final的 引用类型)

③子类初始化, 导致的父类初始化

④Class.forName(类名, true, loader) 或 Class.forName(类名)

⑤new, clone, 反序列化时

37(R(FO`D8OTA2WNVP}J%C9.png

在类加载Student.class类时,static修饰的会被赋值默认值,被static final修饰的基本类型(例如int)会完成赋值操作(假如对象被static final修饰,在初始化阶段才会被赋值(因为是引用类型-有内存地址));等到执行代码Student stu = new Student()时触发类初始化后,static才完成赋值

2%$C0U_6TEV9G))7_Z}}ZMG.png

如何找到类对象地址

3}FHGDXK_~T}G`7UH{X_8RQ.png

final修饰基本类型变量原理

A}}4H(S@K$9X{S`@LUOS9H3.png

①被static final修饰的基本类型,类要是用到了这个值,就会把这个值进行复制到自己的类,因为这个值是static的又是final的,所以根本不会用到Student类,就将被static final修饰的基本类型的值复制了一份放在类中,将来类运行的时候根本不用Student就能取到c和m的值,用的时候就用复制的那一份值就行了,无需用到原始的类型,因此也不会触发原始类型的加载和初始化操作

②如果被static final修饰的基本类型的数值比较小就写死在方法中,如果数值超过了short的最大范围,就会被写在常量池中

链接 中的解析 —— 将常量池的符号引用解析为直接引用

常量池:类的运行过程中需要用到的常量数据;这些常量数据包括一些数值、类名等

在以下代码中,要用到A、B、C,但是一开始A、B、C并没有被加载到内存中,所以这个时候对于这个类来说,仅仅只是知道有A、B、C这些东西,但是具体在内存中什么位置是不知道的,所以此时此刻在这个类的常量池中只保留了A、B、C的符号引用

AQ_)S3Z6DHK)858YYT7{@L9.png

28BY~1)R863UCAFCB1V2ZAI.png

等执行到A a = new A()时,这个时候已经完成类的初始化,符号引用转变为直接引用

K`)[V%URIV9PFV8W)]_OGN5.png