类加载是懒惰的, 首次用到时才加载(下面的初始化条件满足也会导致类加载)
①使用了类.class;②用类加载器的 loadClass 方法加载类
类初始化是懒惰的, 满足条件有
①main方法所在类
②首次访问静态方法或静态变量(非 final, 或 final的 引用类型)
③子类初始化, 导致的父类初始化
④Class.forName(类名, true, loader) 或 Class.forName(类名)
⑤new, clone, 反序列化时
在类加载Student.class类时,static修饰的会被赋值默认值,被static final修饰的基本类型(例如int)会完成赋值操作(假如对象被static final修饰,在初始化阶段才会被赋值(因为是引用类型-有内存地址));等到执行代码Student stu = new Student()时触发类初始化后,static才完成赋值
如何找到类对象地址
final修饰基本类型变量原理
①被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的符号引用
等执行到A a = new A()时,这个时候已经完成类的初始化,符号引用转变为直接引用