• String对象创建相关问题


    无意中看到一个流传年份颇为久远的问题:String s = "a"+"b"+"c"+"d"+"e";  该语句到底一共创建了多少个对象?

    百度了下,找了很多的答案,看到的回复真是令人眼花缭乱,一脸懵逼。

    比如这个问题下的:https://zhidao.baidu.com/question/105991030.html     居然一连串得到了1个、2个、6个、9个、10个一共五种答案。

    在讨论正确答案之前,真的不得不感叹下Java学习路径上的困难,其中之一就是许多问题得到的答案权威性有待考证,你想学习,就必须学会分辨其中的真伪,自己多方收集,多动手实践看底层原理、官方文档。  ——不过,对于一个新手来说,直接看官方文档和底层也不太现实吧,要有前人指引才是最好的。一两句话点破的事情,自己去费时费力的收集资料查证,某种角度上的确是锻炼了你的信息收集能力和耐心,但也是真的消耗时间。

    -------------------------------------------------------下面进入正题:-------------------------------------------------------------

    首先,关于String类,我们要知道的几个原则:

      一:String实例化的方式不同及创建的对象所在的位置也不同:

        方式一:通过字面量的方式来创建对象,如String str = "abc";  这种方式创建的对象就是在方法区中的常量池里。

        方式2:通过new + 构造器的方式创建对象,如String str = new String("abc");  这种方式创建的对象就是在堆空间中开辟空间来存放。

     

      二:字符串拼接方式不同,那么产生的对象所处的内存区域也不同:

        1.常量与常量的拼接结果在常量池。且常量池中不会存在相同内容的常量。

          // String a="ab"+"cd"? //"ab"这样的是常量,a就在常量池中

          // String a="abc";  String b="abc";  //常量池中只有一个"abc"

        2.只要拼接时其中一个是变量,结果就在堆中。

          String s2 = "hadoop";             //s2作为一个栈中的变量,指向常量池中的"hadoop"

          String s6 = "javaEE" + s2;      //s2是变量,所以s6指向堆中

        3.如果拼接的结果调用intern()方法,返回值就在常量池中

          String s2 = "hadoop";  //常量池中

          String s6 = "javaEE" + s2;  //堆中

          String s8 = s6.intern();   //常量池中

        4.如果是final常量和静态池中一般常量的拼接,那么结果还是存在于常量池中

                    final String s4 = "javaEE"; //s4:常量

                    String s5 = s4 + "hadoop"; //s5:常量

    -------------------------------------------------------分割线-------------------------------------------------------------

    好了,既然知道了这两个最重要的原则以及他们的细分情况,那么我们再来讨论下String创建对象可能出现的几种情况:

    (注意,我们讨论这几种情况的前提都是常量池为空)

        情况1:

          String a="abc";  String b="abc";  两个字符串一共创建了几个对象?——1个对象;创建于静态常量池

     

        情况2:

          String str = new String("abc"); ?——2个; 如果字符串池中未找到"abd"这个对象,那么分别在堆中和字符串池中创建一个Stirng类对象

     

        情况3:String a="ab"+"cd"?——1个;

            甲骨文jdk 7中,编译时会进行常量折叠,全字面量字符串相加会折叠为一个字面常量

            编译期:直接将ab和cd进行常量折叠,优化为String a="abcd"; 没有创建对象

            运行期:直接在常量池里查看有没有"abcd",如果有,那么就一个也不创建,如果没有,那就在在常量池里创建1个。

     

        情况4:

          例一

            String s = "aaa" + new String("bbb"); ——创建了4个对象;

              "aaa" 创建一个对象,常量池中

              "bbb" 创建一个对象,常量池中

              new Sring() 创建一个对象,堆中

              "aa" + new String() 创建一个对象,堆中

         

              为了验证最后的"aa" + new String()是在堆中还是在常量池中,我们验证一下

              String str1= "aaa"+new String("bbb");

              String str2 ="aaabbb";  //常量池中

              System.out.println(str1==str2);  //输出为false,说明在堆中

     

          例二

            String str2 = "he" + new String("llo");  ——4个对象;

              "he" 创建一个对象,常量池中

              "llo" 创建一个对象,常量池中

              new String("llo"); 创建一个对象,在堆中

              使用 + 号 jvm会帮我们 创建一个 StringBuilder 对象帮我们进行拼接

                  然后 将拼接完成后的StringBuilder 对象进行toString 又在堆中创建了一个Stirng对象

              以下是代码执行过程的图示

              

        情况5:

           String str=new String("a"+"b");  ——4个对象

            "a"创建一个对象,常量池中

            "b"创建一个对象,常量池中

            "a"+"b"组合"ab"创建一个对象,常量池中

            new String(),创建一个对象,在堆中

            注意,这个堆中的内存里存着的是这字符串"ab"在字符串常量池中的地址

     

     最后附上一些参考:

    https://link.zhihu.com/?target=http%3A//droidyue.com/blog/2014/08/30/java-details-string-concatenation/

    https://droidyue.com/blog/2014/12/21/string-literal-pool-in-java/

     

    如有说错的地方,还请高手多多指正。

  • 相关阅读:
    LeetCode --- Roman to Integer
    LeetCode --- Maximum Depth of Binary Tree
    LeetCode --- Minimum Path Sum
    Hashkell 第一篇
    LeetCode --- Partition List
    LeetCode --- Valid Palindrome
    LeetCode --- Longest Consecutive Sequence
    LeetCode --- Insertion Sort List
    数据库lib7第2, 3题(创建索引和触发器)
    LeetCode --- Reverse Integer
  • 原文地址:https://www.cnblogs.com/tangshun100/p/13211256.html
Copyright © 2020-2023  润新知