该文主要是为了说明final修饰字符串变量在编译期间会得到优化,使用final申明的字符串变量做字符串拼接会等同于直接申明变量。
源程序:
public class AppMain{
public static void main(String[] args){
String a = "hello2";
final String b = "hello";
String c = "hello";
String d = b + 2;
String e = c + 2;
System.out.println(a == d);// true
System.out.println(a == e);// false
}
}
1.编译上段小程序:javac AppMain.java
2.反编译class文件:javap -c AppMain
下面的图片中是该程序反编译后的字节码指令,为了易读所以图片中的字节码指令是省去System.out.println(a == b)与System.out.println(a == e)的结果:
3.解读该程序需要了解的字节码指令
- ldc 将int、float或者String型常量值从常量池中推送至栈顶(方法栈中的操作数栈中)
- astore_1、astore_2、astore_3:将栈顶引用类型的数值存入局部变量表中第二、三、四索引序号的Slot中
- astore index:将栈顶引用类型的数值存入局部变量表中第index索引序号的Slot中
- aload_1、aload_2、aload_3:取局部变量表中第index索引项压入栈顶
- new 创建一个对象,并将其引用压入栈顶
- dup 复制栈顶数值并将复制值压入栈顶
- invokespecial:调用构造方法,实例初始化方法,私有方法
- invokevirtual:调用实例方法
4.运行退main方法,在方法栈弹出前,main方法栈与堆内存中对象说明
图例说明:程序运行结果 变量b、c引用的是常量池中hello这项实例,变量a、d应用常量池中hello2这项实例,而变量e指向的是内存中StringBuilder创建的String对象。