其他博友的不同理解方式:
我们先来看一个类
public class javaPTest { /**常量池 * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub String i1 = "hello"; String i2="world"; String i3="helloworld"; String i4="hello"+"world"; String i5=new String("helloworld"); String i6=new String("helloworld"); System.out.println("helloworld"); System.out.println(i5==i6); System.out.println(i3==i4); }}
result: helloworld false true
why?我们可以通过javap -c javaPTest (前提是:先用javac编译通过) 来看该类的反编译结果
注意: ldc #2 是将常量池中下标为2的常量加载到栈中
astore_1 将栈顶元素存到到当前fame局部变量数组下标为1的变量中,栈顶元素出栈
invokespecial 调用超类构造方法、实例初始化方法、私有方法aload:当前frame的局部变量数组中下标为index的引用型局部变量进栈ldc :将int、float或String型常量值从常量池中推送至栈顶astore i: 将栈顶数值(objectref)存入当前frame的局部变量数组中指定下标(index)处的变量中,栈顶数值出栈。new :创建一个对象,并且其引用进栈dup :复制栈顶数值,并且复制值进栈F:\JAVA\javaIDE\study11.29\src\com\study\main>javap -c javaPTestCompiled from "javaPTest.java"public class com.study.main.javaPTest extends java.lang.Object{public com.study.main.javaPTest(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: returnpublic static void main(java.lang.String[]); Code: 0: ldc #2; //String hello //将string类型常量值(hello)从常量池推送至栈顶 2: astore_1 //将 3: ldc #3; //String world 5: astore_2 6: ldc #4; //String helloworld 8: astore_3 9: ldc #4; //String helloworld 11: astore 4 13: new #5; //class java/lang/String //new了一个String对象,并将其引用进栈, 16: dup 17: ldc #4; //String helloworld 19: invokespecial #6; //Method java/lang/String." ":(Ljava/lang/String;)V 22: astore 5 24: new #5; //class java/lang/String 27: dup 28: ldc #4; //String helloworld 30: invokespecial #6; //Method java/lang/String." ":(Ljava/lang/String;)V 33: astore 6 35: getstatic #7; //Field java/lang/System.out:Ljava/io/PrintStream; 38: ldc #4; //String helloworld 40: invokevirtual #8; //Method java/io/PrintStream.println:(Ljava/lang/String;)V 43: getstatic #7; //Field java/lang/System.out:Ljava/io/PrintStream; 46: aload 5 //将常量数组中下边为5和6的变量加载到栈中(其实两个都存放#4 17行和28行分别表示在数组的4,5下标中,存放#4) 48: aload 6 50: if_acmpne 57 //比较 如果不相等就跳转 53: iconst_1 54: goto 58 57: iconst_0 58: invokevirtual #9; //Method java/io/PrintStream.println:(Z)V 61: getstatic #7; //Field java/lang/System.out:Ljava/io/PrintStream; 64: aload_3 //将常量数组中下边为3和4的变量加载到栈中(其实两个都存放#4 8行和11行分别表示在数组的3,4下标中,存放#4) 65: aload 4 67: if_acmpne 74 70: iconst_1 71: goto 75 74: iconst_0 75: invokevirtual #9; //Method java/io/PrintStream.println:(Z)V 78: return}
我们重点看看String i5=new String("helloworld");对应的反编译代码
13: new #5; //class java/lang/String //new了一个String对象,并将其引用进栈, 16: dup 17: ldc #4; //String helloworld 19: invokespecial #6; //Method java/lang/String."":(Ljava/lang/String;)V 22: astore 5
执行过程中堆栈的变化
所谓的常量池就是在内存中的一个数组,这个数组中记录的都是直面量,并且在数组中,不会出现相同的直面量。