6

可能重复:
关于 Java 字符串池的问题

我对 java Strings 对象的创建有疑问。

String s1 = "Hello"+"world";
String s2 = s1+"Java";

在这个程序中,将创建多少个 String 对象以及如何创建?请解释一下。谢谢。

4

7 回答 7

5

答案是 3

每次 JVM 启动都会创建两个 String 对象:

  • “你好世界”
  • “爪哇”

两者都将被interned,因为它们是常量(在编译时已知)。

每次运行此代码时,它们都会被重用。将创建一个 StringBuilder 来连接上面的两个 String。对它们的引用将分配给 s1 和 s2。

这是代码的字节码:

   0:   ldc #37; //String Helloworld
   2:   astore_1
   3:   new #39; //class java/lang/StringBuilder
   6:   dup
   7:   aload_1
   8:   invokestatic    #41; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
   11:  invokespecial   #47; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
   14:  ldc #50; //String Java
   16:  invokevirtual   #52; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
   19:  invokevirtual   #56; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
   22:  astore_2
   23:  return
于 2013-01-07T04:22:02.177 回答
5

您不能真正说出String创建了多少个 s,因为由于 JVM 的不同实现而存在一些差异。

作为String一个不可变的类,天真的答案是 5。但是经过一些优化(例如,使用StringBuffer/ StringBuilder只会有 2String秒。

因为 concats 将通过 -calls 进行汇总append()

编辑:因为这里有一些不同的答案,所以我说 5 的解释:

  1. “你好”
  2. “世界”
  3. (s1) “你好世界”
  4. “爪哇”
  5. (s2) “HelloworldJava”
于 2013-01-07T04:23:57.960 回答
2

如果你看编译后的代码,你可以很容易地猜到:

String s1 = "Helloworld";
String s2 = (new StringBuilder(String.valueOf(s1))).append("Java").toString();

我们不能仅仅通过查看源代码来准确地知道,因为许多优化都是由编译器在执行之前完成的。

在这里,我们看到为 s1 创建了 1 个 String 对象,为 s2 创建了另一个 String 对象。字符串池中有 2 个字符串文字:“Helloworld”和“Java”

于 2013-01-07T04:27:41.813 回答
1

如果你反编译你的 Program.class 你会看到真正的代码

String s1 = "Helloworld";
String s2 = (new StringBuilder(String.valueOf(s1))).append("Java").toString();

似乎有 10 个对象,因为在每个 String 内部都有char[] value一个单独的对象 + StringBuilder 内部的另一个 char[]

于 2013-01-07T04:27:04.553 回答
0

答案是3。

您可以通过以下方式查看反汇编结果:

javap -verbose YourClass

常量池包括:

...
const #17 = Asciz       Helloworld;
...
const #30 = Asciz       Java;
...

这意味着两个字符串(“Helloworld”和“Java”)是编译时常量表达式,将自动被嵌入常量池中。

编码:

Code:
 Stack=3, Locals=3, Args_size=1
 0:   ldc     #16; //String Helloworld
 2:   astore_1
 3:   new     #18; //class java/lang/StringBuilder
 6:   dup
 7:   aload_1
 8:   invokestatic    #20; //Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
 11:  invokespecial   #26; //Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
 14:  ldc     #29; //String Java
 16:  invokevirtual   #31; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
 19:  invokevirtual   #35; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
 22:  astore_2
 23:  return

它表示 s2 是由 StringBuilder.append() 和 toString() 创建的。

为了让这更有趣,javac 可以优化常量折叠中的代码。您可以猜测以下代码创建的字符串的数量:

final String s1 = "Hello" + "world";
String s2 = s1 + "Java";

“final”表示 s1 是常量,可以帮助 javac 构建 s2 和实习生 s2 的值。所以这里创建的字符串数是 2。

于 2013-01-07T07:36:07.250 回答
-1

是的,将创建五个 String 对象。字符串是不可变的;以下是步骤 - 1. 首先是“Hello” 2. 然后是另一个对象“Hello World” 3. 然后是另一个对象“Java” 4. 然后是 s1+“Java”,最后是 s2。

于 2013-01-07T04:34:07.483 回答
-2

实际上,不会只创建两个 String 字面量的 String 对象。当字符串像你一样被初始化时,它们是文字而不是对象。如果您想创建 String 对象,您将执行以下操作

String a = new String("abcd");
于 2013-01-07T04:24:44.090 回答