常量
Java中由final修饰的就是常量。如下:
public static final int a = 1;
public final int b = 1;
public static final String str = UUID.randomUUID().toString();
分类:编译期常量和运行时常量
编译期常量:它的值在编译期就可以确定的常量。
运行时常量:它的值在运行时动态计算的。
二者的根本区别体现在与类的初始化关系上面。
编译期常量在编译阶段会存入到调用这个常量的方法所在类的常量池中,本质上,调用类并没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。而运行时常量会导致直接使用,也就会导致类的初始化。
public class MyTest {
public static void main(String[] args) {
//第一处
System.out.println(Parent.str);
}
}
class Parent {
//第二处
public static final String str = "test";
//第三处
static {
System.out.println("Parent");
}
}
运行结果是 打印test。并没有打印第三处的静态代码块。也就是没有初始化Parent类。
原因如下:
因为str是编译期常量,在编译期就已经确定是"test",并且不会发生改变。 然后将该"test"存入到MyTest的常量池中,MyTest类也就没有直接引用Parent类,因此不会触发Parent类的初始化,也就不会运行Parent类的静态代码块。
如果将str变为运行时常量会导致Parent类的初始化。
public class MyTest {
public static void main(String[] args) {
System.out.println(Parent.str);
}
}
class Parent {
//第一处 将上例中的"test",改为new(运行时创建)
public static final String str = new String();
static {
System.out.println("Parent");
}
}
运行结果是 打印Parent。运行了静态代码块。也就是初始化了Parent类。
既然编译期常量在运行阶段,并不影响程序结果,将Parent.class删除也不会影响程序结果。测试如下:
java MyTest 正确输出
利用IDE终端反编译字节码 javap -c 类名
助记符
getstatic 调用静态变量
ldc 表示将int、float、String类型的常量值,从常量池中推送至栈顶
bipush 表示将(-128—127)的常量值,从常量池中推送至栈顶
sipush 表示将短整型的常量值,从常量池中推送至栈顶
iconst_(-1-5) 表示将-1---5这七个值,从常量池中推送至栈顶
anewarray 表示创建一个引用类型的数组,并将其压入栈顶
anewarray 表示创建一个原始的数组,并将其压入栈顶
网友评论