• 用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:JAVAjavaIDEstudy11.29srccomstudymain>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
    

    执行过程中堆栈的变化 

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

     

  • 相关阅读:
    java 各种运行组件下载地址
    Exchange 2013故障XOWAError: System.NullReferenceException
    已整理sshpass 脚本应用案例
    已整理head 与 tail 的特殊用法(除尾行和去掉首行)
    如何删除exchange 2013 邮件队列
    分布式事务锁
    GRPC
    identityserver4 Showing login: User is not authenticated
    Selenium 中的 JUnit 注解
    Groovy语境下的Map
  • 原文地址:https://www.cnblogs.com/fjsnail/p/3473611.html
Copyright © 2020-2023  润新知