老生常谈-- String aa="aaa", String aa=new String("aaa");

老生常谈的问题

        String aa="aaa";
        String cc=new String ("aaa");
         的区别 ?
                
代码

public class T{

       public static void main(String args[]){
       String aa="aaa";
       String cc=new String ("aaa");
        }
   }
     1.通过java自带工具javap 得到运行使得指令集

    Code:
   0:   aload_0
   1:   invokespecial   #8; //Method java/lang/Object."<init>":()V
   4:   return

  public static void main(java.lang.String[]);
  Code:
   0:   ldc     #16; //String aaa
   2:   astore_1

   3:   new     #18; //class java/lang/String
   6:   dup
   7:   ldc     #16; //String aaa
   9:   invokespecial   #20; //Method java/lang/String."<init>":(Ljava/lang/String;)V

   12:  astore_2
   13:  return

   只看有关部分:

   0:   ldc     #16; //String aaa
   2:   astore_1
  
  String aa="aaa";    对应

  ldc:                 从常量池(加载类时,将数字、字符、字符创常量导入方法区,

                            具体存储请看有关jvm内存模型 资料) 中得到字符串对  象("aaa"),压入栈中;
  astore_1:       取栈中数据(赋值给aa)


  String cc=new String ("aaa");   对应
   3:   new     #18; //class java/lang/String
   6:   dup
   7:   ldc     #16; //String aaa
   9:   invokespecial   #20; //Method java/lang/String."<init>":(Ljava/lang/Stri
           
   3:   new     #18; //class java/lang/String 创建对象
   6:   dup   复制栈顶压入栈
   7:   ldc     #16; //String aaa
   9:   invokespecial   #20; //Method java/lang/String."<init>":(Ljava/lang/Stri  调用构造方法


  

   由此可知,aa 等内容就是常量池中字符串常量"aaa"的地址
             cc 是以字符串常量"aaa"为参数新构造的字符串对象


  
    由此 以下问题就显而易见了

     String aa="aaa";
     String bb="aaa";
     String cc=new String("aaa");
     System.out.println(aa==bb); true//aa,bb都是方法区中字符串常量那个对象,

                                                           一个地址 (aa==bb就相当于 aa==aa 或 bb==bb)
     System.out.println(aa=cc);  false //cc可以看成是以aa为参数,new的字符串

2.通过java 自带工具jmap(jdk1.6以后)查看此过程创建了几个对象

   jmap -histo {pid}
num     #instances         #bytes  class name
----------------------------------------------
11:          1951           46824  java.lang.String

若运行String aa="aaa"; 以后
num     #instances         #bytes  class name
----------------------------------------------
11:          1952           46848  java.lang.String

可以看到 增加了1个 String 实例,对象就是 aa指向的字符串常量对象

若运行String cc=new String("aaa"); 以后
num     #instances         #bytes  class name
----------------------------------------------
  11:          1953           46872  java.lang.String

可以看到 增加了2个 String 实例,其中包括 常量池中字符串常量对象 ,还有 new的cc对象

若运行String aa="aaa"; String cc=new String("aaa"); 以后
num     #instances         #bytes  class name
----------------------------------------------
  11:          1953           46872  java.lang.String
虽然两个语句都运行,但只增加了2个对象,常量池中字符串常量对象,new的cc对象

(常量池中字符串常量创建一次,并且共享数据)


ldc指令格式:ldc,index

ldc指令过程:

要执行ldc指令,JVM首先查找index所指定的常量池入口,在index指向的常量池入口,
JVM将会查找CONSTANT_Integer_info,CONSTANT_Float_info和CONSTANT_String_info入口。
如果还没有这些入口,JVM会解析它们。而对于上面的hahaJVM会找到CONSTANT_String_info入口,
同时,将把指向被拘留String对象(由解析该入口的进程产生)的引用压入操作数栈。


3.做下面测试(使用javap,和jmap工具,jdk版本1.6)

  

public static void main(String args[]){

            //10:          1935           46440  java.lang.String
    String aa="aaa";
            //10:          1936           46464  java.lang.String
    String bb="aa"+"a"; //编译时在class文件中编译器只保留"aaa" 字符串常量,可以通过javap命令知道
            //10:          1936           46464  java.lang.String
    String dd="aaa";
            //10:          1936           46464  java.lang.String
    String ee="bbb";
            //10:          1937           46488  java.lang.String
String cc=new String ("aaa");
            //10:          1938           46512  java.lang.String
          
          t();
}
public static void t(){
            //10:          1938           46512  java.lang.String
            String aa="aaa";
            //10:          1938           46512  java.lang.String
            String bb="aa"+"a";
            //10:          1938           46512  java.lang.String
            String dd="aaa";
            //10:          1938           46512  java.lang.String
            String ee="bbb";
            //10:          1938           46512  java.lang.String
            String cc=new String ("aaa");
            //10:          1939           46536  java.lang.String
}
    
注: 测试 aa==bb==cc true

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值