【发布时间】:2012-12-20 19:42:16
【问题描述】:
我对 java Strings 对象的创建有疑问。
String s1 = "Hello"+"world";
String s2 = s1+"Java";
在这个程序中将创建多少个 String 对象以及如何创建?请解释一下。 谢谢。
【问题讨论】:
我对 java Strings 对象的创建有疑问。
String s1 = "Hello"+"world";
String s2 = s1+"Java";
在这个程序中将创建多少个 String 对象以及如何创建?请解释一下。 谢谢。
【问题讨论】:
答案是 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
【讨论】:
你不能说创建了多少Strings,因为由于JVM的不同实现存在一些差异。
由于String 是一个不可变类,天真的答案是 5。但经过一些优化(例如,使用 StringBuffer/StringBuilder 将只有 2 个Strings。
因为 concats 将通过 append()-calls 进行汇总。
编辑:因为这里有一些不同的答案,所以解释了我为什么说 5:
【讨论】:
Stringbuffer和StringBuilder的部分。编译器将使用这些来最小化使用的文字数量。
如果你看编译后的代码,你很容易猜到:
String s1 = "Helloworld";
String s2 = (new StringBuilder(String.valueOf(s1))).append("Java").toString();
我们不能仅仅通过查看源代码来准确地知道,因为许多优化都是在执行之前由编译器完成的。
这里我们看到为 s1 创建了 1 个 String 对象,为 s2 创建了另一个 String 对象。字符串池中有 2 个字符串文字:“Helloworld”和“Java”
【讨论】:
如果你反编译你的 Program.class 你会看到真正的代码
String s1 = "Helloworld";
String s2 = (new StringBuilder(String.valueOf(s1))).append("Java").toString();
似乎是 10 个对象,因为每个 String 内部都有 char[] value 这是一个单独的对象 + StringBuilder 内部的另一个 char[]
【讨论】:
答案是 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。
【讨论】:
是的,将创建五个 String 对象。字符串是不可变的;以下是步骤 - 1.第一个“你好” 2.然后是另一个对象“Hello World” 3.然后是另一个对象“Java” 4.然后s1+"Java" 然后最后会创建 s2。
【讨论】:
实际上不会只创建两个字符串字面量的字符串对象。 当字符串像你一样被初始化时,它们是文字而不是对象。如果您想创建 String 对象,您可以执行以下操作
String a = new String("abcd");
【讨论】: