用jvm指令分析String 常量池

其他博友的不同理解方式:  http://hi.baidu.com/boywell/item/d5ee5b0cc0af55c875cd3cfd 

我们先来看一个类

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 javaPTest
Compiled 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."<init>":()V
   4:   return

public 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."<init>":(Ljava/lang/Strin g;)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."<init>":(Ljava/lang/Strin g;)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/Str ing;)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."<init>":(Ljava/lang/Strin
g;)V
   22:  astore  5

执行过程中堆栈的变化 

所谓的常量池就是在内存中的一个数组,这个数组中记录的都是直面量,并且在数组中,不会出现相同的直面量。

 

 

posted @ 2013-12-13 17:46  Jackvin  阅读(750)  评论(0编辑  收藏  举报