编译期常量
2022-11-22
编译期常量
先说结论,编译期常量=final+常量
java四个阶段
- 编辑期
- 编译期:将.java文件编译为.class文件
- 加载期:将.class文件加载到内存 并 生成.class类
- 运行期:通过.class类去创建对象、执行代码
参考:https://www.modb.pro/db/211851
除了第一个阶段我们能直接干预,剩余三个阶段,都是jvm自己执行的。第二阶段是 非人工干预的 第一阶段。在这个阶段就能确定的值,我们就称为**「编译期常量」。那么即使后面第三阶段和第四阶段不走,对它也没有影响,而类加载就发生在第三阶段,所以: 「编译期常量不会触发类加载」。
编译期常量定义方式
// final定义,且是常量,即为编译期常量。而且,编译期常量不存在赋值语句,只存在初始化语句。
public final int a = 10000;
public static final int b = 10000;
反例:
public int a = 10; // 没用final修饰,不是编译期常量
public final int b = System.currentTimeMillis(); // 值不是常量,所以不是编译期常量
编译期常量的表现
编译后的.class文件中,编译期变量被**「ConstantValue」**修饰。
public class Class {
public final int a = 10000;
public static final int b = 10000;
}
// 查看编译后...
public final int a;
descriptor: I
flags: (0x0011) ACC_PUBLIC, ACC_FINAL
ConstantValue: int 10000 // 有ConstantValue,说明是编译期常量
public static final int b;
descriptor: I
flags: (0x0019) ACC_PUBLIC, ACC_STATIC, ACC_FINAL
ConstantValue: int 10000 // 有ConstantValue,说明是编译期常量
此外
被static修饰的是类一级的,非static修饰的是对象一级的。对象一级的要先创建对象才能使用,所以肯定会触发类加载(不管是不是编译期常量)。
在实际开发中,如果A类之前调用到了B类的编译期常量,当修改B的编译期常量值后,还需要再次编译A类,否则A类对于该值的调用还是修改之前的值(因为已经固定在class文件里了)。