美文网首页我爱编程
专题整理之—String的字符串常量池

专题整理之—String的字符串常量池

作者: 你想要怎样的未来 | 来源:发表于2018-11-27 00:27 被阅读9次

    为了加深对Java语言的理解,加深对Java各种特性的理解与掌握,平常会自己归纳一些专题的分析和总结。基于自己的理解,感觉哪些部分适合在一起进行总结,就归纳为一个专题了。可能一个专题里面的东西也不属于一个类别,或者也比较杂乱,请见谅。
    本文是在总结不可变对象与String的不可变中,涉及到的String的字符串常量池。感觉这个部分比较重要,面试也经常考到这些,就单独拿出来作为一个专题。(此篇总结大部分是借鉴了CSDN的一篇文章,然后加上了一些自己的理解)

    字符串常量池:

    • 为了减少在jvm中创建的字符串的数量,字符串类维护了一个字符串常量池,字符串常量池(String pool)是Java堆内存中一个特殊的存储区域;
    • 当创建String对象时,jvm会先检查字符串常量池,如果这个字符串的常量值已经存在在池中了,就直接返回池中对象的引用,如果不在池中,就会实例化一个字符串并放入池中;
    • 常量池:用于保存java在编译期就已经确定的,已经编译的class文件中的一份数据。包括了类、方法、接口中的常量,也包括字符串常量,如String s = "a"这种声明方式;
    String s1 = "aaa";
    String s2 = "aaa";
    
    1PAI~[D5DA))%XZ~5S6])RH.png

    从日常的面试题展开:

    String s = new String("abc"); //创建了几个对象
    

    两个;
    第一个对象是"abc"字符串存储在常量池中;
    第二个对象是创建在Heap中的String对象;这里的s是放在栈里面的指向了Heap堆中的String对象。

    String s1 = new String("s1") ;
    String s2 = new String("s1") ; //创建了几个对象
    

    三个;
    第一个是编译期就已经创建在常量池中创建的"s1",因为创建一个之后常量池中就会有,不再创建,直接指向;
    后面两个是运行期使用new创建在堆上的s1和s2;

    示例1:

    String s0 = "111";              //pool
    String s1 = new String("111");  //heap
    final String s2 = "111";        //pool
    String s3 = "sss111";           //pool
    String s4 = "sss" + "111";      //pool
    String s5 = "sss" + s0;         //heap 
    String s6 = "sss" + s1;         //heap
    String s7 = "sss" + s2;         //pool
    String s8 = "sss" + s0;         //heap
     
    System.out.println(s3 == s4);   //true
    System.out.println(s3 == s5);   //false
    System.out.println(s3 == s6);   //false
    System.out.println(s3 == s7);   //true
    System.out.println(s5 == s6);   //false
    System.out.println(s5 == s8);   //false
    

    示例2:

    String str1 = "abc";
    String str2 = "abc";
    String str3 = "abc";
    String str4 = new String("abc");
    String str5 = new String("abc");
    String str6 = new String("abc");
    
    @DPKA4RS@H{0GJJ7SH)FPP8.png

    结论:

    1. 单独使用""引号创建的字符串都是常量,编译器就已经存储到常量池中了;
    2. 使用new String()创建的是对象会存储到heap中,是运行期创建的;
    3. 使用只包含常量的字符串连接符如"a"+"a"创建的也是常量,编译器就能确定,并存储到常量池"aa",但不会有"a"存在;
    4. 使用包含变量的字符串连接符如"a"+s1创建的对象会存储在堆中,运行时期才创建;只要s1是变量,不论s1指向池常量池中的字符串对象还是堆中的字符串对象,运行期"a"+s1操作实际上是编译器创建了StringBuilder对象进行了append操作后通过toString()返回了一个字符串对象存在heap上。
    5. 对于final String s2 = "111",是一个用final修饰的变量,在编译期就已知了,在包含变量的字符串连接符"a"+s2时直接用常量"111"来代替s2,等效于"a"+"111",在编译期就已经生产了字符串对象"a111"对象在常量池中。

    目前全部文章列表:
    idea整合restful风格的ssm框架(一)
    idea整合restful风格的ssm框架(二)
    idea整合spring boot+spring mvc+mybatis框架
    idea整合springboot+redis
    JVM学习之—Java内存区域
    JVM学习之—垃圾回收与内存分配策略
    专题整理之—不可变对象与String的不可变
    专题整理之—String的字符串常量池

    相关文章

      网友评论

        本文标题:专题整理之—String的字符串常量池

        本文链接:https://www.haomeiwen.com/subject/dmkwqqtx.html