可能重复:
关于 Java 字符串池的问题
我对 java Strings 对象的创建有疑问。
String s1 = "Hello"+"world";
String s2 = s1+"Java";
在这个程序中,将创建多少个 String 对象以及如何创建?请解释一下。谢谢。
可能重复:
关于 Java 字符串池的问题
我对 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
您不能真正说出String
创建了多少个 s,因为由于 JVM 的不同实现而存在一些差异。
作为String
一个不可变的类,天真的答案是 5。但是经过一些优化(例如,使用StringBuffer
/ StringBuilder
只会有 2String
秒。
因为 concats 将通过 -calls 进行汇总append()
。
编辑:因为这里有一些不同的答案,所以我说 5 的解释:
如果你看编译后的代码,你可以很容易地猜到:
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. 首先是“Hello” 2. 然后是另一个对象“Hello World” 3. 然后是另一个对象“Java” 4. 然后是 s1+“Java”,最后是 s2。
实际上,不会只创建两个 String 字面量的 String 对象。当字符串像你一样被初始化时,它们是文字而不是对象。如果您想创建 String 对象,您将执行以下操作
String a = new String("abcd");