【问题标题】:How many Strings are created in memory?在内存中创建了多少个字符串?
【发布时间】:2015-04-28 01:39:29
【问题描述】:

假设我有这个String 表达式

String hi = "Tom" + "Brady" + "Goat"

我知道字符串池“允许运行时通过在池中保留不可变字符串来节省内存”String Pool

字符串池中会创建多少个字符串?

我最初的猜测是 5 - "Tom""Brady""Goat""TomBrady""TomBradyGoat",因为 String 连接的操作顺序(从左到右?)还是只有存储在字符串池中的最终结果“TomBradyGoat”?

【问题讨论】:

    标签: java concatenation heap-memory string-concatenation string-pool


    【解决方案1】:

    您在这里拥有的是一个常量表达式,由JLS, Section 15.28 定义。

    常量表达式是表示原始类型值或字符串的表达式,它不会突然完成并且仅使用以下内容组成:

    • 原始类型的文字和字符串类型的文字(§3.10.1、§3.10.2、§3.10.3、§3.10.4、§3.10.5)

    • 转换为基本类型和转换为 String 类型(第 15.16 节)

    • 一元运算符 +、-、~ 和 ! (但不是 ++ 或 --)(§15.15.3、§15.15.4、§15.15.5、§15.15.6)

    • 乘法运算符 *、/ 和 %(第 15.17 节)

    • 加法运算符 + 和 - (§15.18)

    (其他可能性)

    编译器确定表达式"Tom" + "Brady" + "Goat" 是一个常量表达式,因此它会将表达式本身计算为"TomBradyGoat"

    JVM 将在字符串池中只有一个字符串,"TomBradyGoat"

    【讨论】:

      【解决方案2】:

      在运行时,这段代码将转换为单个 String 对象。编译器将在编译时处理连接并在常量池中添加单个值。

      【讨论】:

        【解决方案3】:

        其他答案很好地解释了为什么只有 1 个字符串被添加到字符串池中。但是,如果您想自己检查并进行一些测试,您可以查看字节码以查看创建并添加到字符串池的 String 的数量。例如:

        Ex1:

        public static void main(String[] args) {
            String hi = "Tom" + "Brady" + "Goat";
        }
        

        字节码:

          // access flags 0x9
          public static main(String[]) : void
           L0
            LINENUMBER 6 L0
            LDC "TomBradyGoat"
            ASTORE 1
           L1
            LINENUMBER 7 L1
            RETURN
           L2
            LOCALVARIABLE args String[] L0 L2 0
            LOCALVARIABLE hi String L1 L2 1
            MAXSTACK = 1
            MAXLOCALS = 2
        

        如您所见,只创建了 1 个字符串

        Ex2:

        public static void main(String[] args) {
                String str1 = "Tom";
                String str2 = "Brady";
                String str3 = "Goat";
                String str = str1 + str2 + str3;
        }
        

        字节码:

          // access flags 0x9
          public static main(String[]) : void
           L0
            LINENUMBER 6 L0
            LDC "Tom"
            ASTORE 1
           L1
            LINENUMBER 7 L1
            LDC "Brady"
            ASTORE 2
           L2
            LINENUMBER 8 L2
            LDC "Goat"
            ASTORE 3
           L3
            LINENUMBER 9 L3
            NEW StringBuilder
            DUP
            ALOAD 1: str1
            INVOKESTATIC String.valueOf (Object) : String
            INVOKESPECIAL StringBuilder.<init> (String) : void
            ALOAD 2: str2
            INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
            ALOAD 3: str3
            INVOKEVIRTUAL StringBuilder.append (String) : StringBuilder
            INVOKEVIRTUAL StringBuilder.toString () : String
            ASTORE 4
           L4
            LINENUMBER 10 L4
            RETURN
           L5
            LOCALVARIABLE args String[] L0 L5 0
            LOCALVARIABLE str1 String L1 L5 1
            LOCALVARIABLE str2 String L2 L5 2
            LOCALVARIABLE str3 String L3 L5 3
            LOCALVARIABLE str String L4 L5 4
            MAXSTACK = 3
            MAXLOCALS = 5
        

        如您所见,创建了 4 个字符串

        【讨论】:

        【解决方案4】:

        正如其他人所提到的,编译器足以优化这个非常简单的示例,但如果您有更复杂的功能(这可能是您关心的),它可能不会。例如:

        String a = "Tom";
        String b = "Brady";
        String c = a;
        c += b;
        

        这将导致创建 3 个字符串。

        【讨论】:

        • 这不是“足够好”的问题。 JLS 要求编译器将 OP 的表达式视为常量表达式并创建单个字符串。
        猜你喜欢
        • 2012-06-26
        • 1970-01-01
        • 1970-01-01
        • 2016-03-03
        • 2021-06-26
        • 2019-09-19
        • 1970-01-01
        • 2016-06-19
        • 2019-12-29
        相关资源
        最近更新 更多