以下代码创建了多少个String对象?
String x = new String("xyz");
String y = "abc";
x = x + y;
我访问了很多网站,其中一些人说这行代码创建了3个对象,有些人说它创建了4个。我只是想知道在执行这行代码后创建了多少个对象。
答案 0 :(得分:49)
在运行结束时,将有四个String
个对象:
String
文字"xyz"
new String("xyz")
String
文字"abc"
String
"xyz" + "abc"
醇>
真正的问题是将部分或全部这些对象归因于您的程序。可以合理地声称您的代码只创建了两个或多达四个String
。尽管总共有四个String
个对象,但对象1和3可能不一定由代码创建,因为它们位于常量池中,因此它们是在代码的直接控制之外创建的。
答案 1 :(得分:16)
本答案旨在纠正一些其他答案所引起的误解:
例如:
编译器可能会用x + y替换常量(“xyzabc”)。 @Binkan Salaryman
...和String对象4 [对应于串联的字符串]可以由编译器计算并转换为实习常量。 @dasblinkenlight
这是不正确的。 JLS说明了这一点:
15.18.1。 String Concatenation Operator +
...
除非表达式是常量表达式(第15.28节),否则新创建String对象(第12.5节)。
为了成为常量表达式,表达式中的变量名必须是:
引用常量变量的简单名称(第6.5.6.1节)(§4.12.4)。
其中“常量变量”定义为:
常量变量是基本类型或类型String的最终变量,使用常量表达式初始化(第15.28节)。
在此示例中,x
或y
都不是final
,因此它们不是常量变量。即使它们是final
,y
仍然不会是常量变量,因为在初始化中使用了new
运算符。
简而言之,Java编译器不允许使用内联常量"xyzabc"
作为连接表达式的结果。
如果我在最后添加以下声明:
System.out.println(x == "xyzabc");
它将始终打印false
...假设编译器符合Java语言规范。
答案 2 :(得分:12)
看看反编译的课程,你会看到一切:)答案应该是:
"xyz"
和"abc"
)仅引用常量池中的位置,因此这些不是由您的代码创建的new String("xyz")
)字符串连接由编译器优化并更改为StringBuilder,以便间接创建最后一个字符串
public java.lang.String method();
descriptor: ()Ljava/lang/String;
flags: ACC_PUBLIC
Code:
stack=3, locals=3, args_size=1
0: new #2 // class java/lang/String
3: dup
4: ldc #3 // String xyz
6: invokespecial #4 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: ldc #5 // String abc
12: astore_2
13: new #6 // class java/lang/StringBuilder
16: dup
17: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
20: aload_1
21: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: aload_2
25: invokevirtual #8 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
28: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_1
32: aload_1
33: areturn
答案 3 :(得分:8)
答案是 4 。
由于您使用了new
关键字,Java将在普通(非池)内存中创建一个新的String对象,x
将引用它。除此之外,文字“xyz”将被放置在字符串池中,这又是另一个字符串对象。
所以,4个字符串对象是:
如果您的代码是这样的:
String x = "xyz";
String y = "abc";
x = x + y;
然后答案是 3 。
注意:字符串#4位于非池内存中,因为字符串文字和通过计算常量表达式生成的字符串(请参阅JLS§15.28)是唯一隐式实现的字符串。
来源:SCJP Sun认证Java 6程序员(页面:434,第6章)
答案 4 :(得分:7)
如果要测试实例,请运行此代码段并查看输出:
import static java.lang.System.identityHashCode;
public class Program {
public static void main(String... args) {
String x = new String("xyz");
String y = "abc";
String z = x + y;
System.out.printf("x: %d | %d\n", identityHashCode(x), identityHashCode(x.intern()));
System.out.printf("y: %d | %d\n", identityHashCode(y), identityHashCode(y.intern()));
System.out.printf("z: %d | %d\n", identityHashCode(z), identityHashCode(z.intern()));
}
}
我使用 jdk1.7.0_67 :
获得以下输出x:414853995 | 1719175803个
y:1405489012 | 1405489012个
z:1881191331 | 1881191331
总共有4个String
个实例......
答案 5 :(得分:3)
new String(”xyz“)
肯定会创建一个新实例。 "abc"
和"xyz"
存储在类常量池中,x = x + y
在引擎盖下创建StringBuilder
,因此会创建new String
,因此字符串数量为4这里。
但编译器可能会用x + y
替换常量("xyzabc"
)。
答案 6 :(得分:3)
我会说 4 因为:
x + y
will be replaced by the compiler with a StringBuilder
implementation. +1 new
always creates a new object. +1 以下是:
String x = new String("xyz"); // 2 objects created: the variable and the constant
String y = "abc"; // 1 object created: the variable
x = x + y; // 1 object created: the one by the StringBuilder class
答案 7 :(得分:3)
你看到问题的不同答案的原因(部分)是不明确的。
“以下代码创建了多少个String对象?”
歧义在于“由以下代码创建”:
是否询问(仅)执行代码所创建的String对象的数量?
或者......是否询问在执行代码期间需要存在的String对象的数量?
你可能会争辩说代码隐式地创建了与文字对应的String对象,而不是在运行时,而是在加载时。但是,这些对象可以与使用相同文字的其他代码共享。 (如果你看起来很难,那么在类加载过程中可能会创建包含相同字符串的其他字符串对象。)
您看到不同答案的另一个原因是,创建的字符串数量并不完全清楚。各种规范规定在某些点创建新的String对象将,但是关于是否可以创建中间String对象有“蠕动空间”。
例如,JLS声明new
总是创建一个新对象,并且字符串连接运算符创建一个新对象,除非在某些明确指定的情况下(参见我的其他答案)。但是,规范并不禁止在幕后创建其他字符串。
但在这种情况下,如果我们假设我们使用的是现代热点JVM,那么:
new
和+
运算符)。这些4字符串的存在/创建由JLS保证。
答案 8 :(得分:1)
答案是 4
String x = new String("xyz");//First Object
String y = "abc";//Second Object
x = x + y;//Third, fourth Object
答案 9 :(得分:1)
有时候让字节代码说话会更好 使用JAVAP检查代码
public static void main(java.lang.String[]);
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=3, args_size=1
0: new #16 // class java/lang/String
3: dup
4: ldc #18 // String xyz
6: invokespecial #20 // Method java/lang/String."<init>":(Ljava/lang/String;)V
9: astore_1
10: ldc #23 // String abc
12: astore_2
13: new #25 // class java/lang/StringBuilder
16: dup
17: aload_1
18: invokestatic #27 // Method java/lang/String.valueOf:(Ljava/lang/Object;)Ljava/lang/String;
21: invokespecial #31 // Method java/lang/StringBuilder."<init>":(Ljava/lang/String;)V
24: aload_2
25: invokevirtual #32 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/St
ringBuilder;
28: invokevirtual #36 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: astore_1
32: return
LineNumberTable:
line 6: 0
line 7: 10
line 8: 13
line 9: 32
LocalVariableTable:
Start Length Slot Name Signature
0 33 0 args [Ljava/lang/String;
10 23 1 x Ljava/lang/String;
13 20 2 y Ljava/lang/String;
}
现在从代码中看到
At `0: new` Creates a new String Object
At `3:dup` ; make an extra reference to the new instance
At `4:ldc #18` as seen literal "xyz" has been placed in the pool (one string Object)
At `6: invokespecial;` ; now call an instance initialization method with parameter and creates a object in nonpool memory.
At `9: astore_1` Stores the above reference in local variable 1(i.e x)
所以此时我们有两个String对象
At `10:ldc #23` as seen literal "abc" has been placed in the pool (third string )
At `12: astore_2` Stores the above reference in local variable (i.e y)
所以到这个时候我们有三个String Object
28: invokevirtual #36 // Method java/lang/StringBuilder.toString:
()Ljava/lang/String;;(fourth String Object is Created)
所以我们在这段代码中总共有四个String对象。
由于我是编程的新手并且已经开始学习,仅仅几个月后我就会指出我是否在某个地方出错了,它的正确版本是什么。谢谢:))
答案 10 :(得分:1)
validates_uniqueness_of :name, :scope => :place
字符串是不可变的,因此如果需要更改任何现有的字符串变量,则将创建新对象以进行分配。第1行,第2行是字符串对象,其中第3行是对现有字符串变量的修改,因此需要进行新的分配以添加x + y。所以它应该创建创建3个对象。
答案 11 :(得分:-1)
1。在堆区域中创建的对象 “ xyz” //由'String x'和 xyzabc //由“ x + y”(串联)创建
2。在scp中创建的对象(字符串常量池) “ xyz” //为将来的目的而创建,不适用于垃圾收集和 “ abc” //由“字符串y”文字创建
因此在这种情况下创建的对象总数为4
答案 12 :(得分:-1)
答案是5