参考《深入理解java虚拟机第三版》 第七章
自己看的时候的一些混淆点:
- “加载”和“类加载”不是一个概念,“加载”是“类加载”的第一步;
- 类加载过程包括 加载、验证、准备、解析、初始化。验证、准备、解析统称为连接。对类进行初始化前加载、验证、准备必须已经开始,而解析在某些情况下可以在初始化阶段后再开始(动态绑定机制(多态、方法重写))
- 类加载的准备阶段会为类的静态变量(static)分配内存并设置类初始值,这里的初始值是初始0值,int置0,boolean置false,引用类型reference置null。
- 类初始化就是执行类构造器< clinit >()方法的过程。在多线程环境下会被正确地加锁同步,只有一个线程会执行该方法。
- 类初始化阶段才会真正执行静态语句块和为静态变量赋初始值的操作。
- 静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,可以赋值但不能访问。
public class Test {
static {
i = 0; //可以正常编译通过
System.out.println(i); //报错“非法前向引用”
}
static int i = 1;
}
- 类初始化后,才能创建该类的实例对象。
- 外部类实例化后,内部类才能进行类加载。
- 非静态内部类不能有静态变量,这应该只是一种规定,感觉没必要深究。
public class Outer{
class Inner
{
int j = 0; // 允许
static int k; // 不允许
static final int i = 1; //允许
static final Date DATE = new Date(); //不允许
}
}
- Class文件中的常量池表会存放编译器生成的各种字面量和符号引用。字面量即 String s = “str"的"str”,int i = 1的1。static final Date DATE = new Date()的new Date() 不属于 字面量,它只会存储一个符号引用,符号引用只是定位目标对象用的,是字面量的形式,不包含目标对象内部的任何信息。
具体还得看书。