计算由Java代码创建的字符串对象
以下代码创建了多少个字符串对象计算由Java代码创建的字符串对象,java,string,Java,String,以下代码创建了多少个字符串对象 String x = new String("xyz"); String y = "abc"; x = x + y; 我访问过很多网站,有人说这行代码创建了3个对象,有人说它创建了4个对象。我只是想知道在执行这行代码之后创建了多少个对象。新字符串(“xyz”)当然会创建一个新实例。“abc”和“xyz”存储在类常量池中,x=x+y在引擎盖下创建一个StringBuilder,从而创建一个新字符串,因此这里的字符串计数为4 编译器可能会用常量(“xyzabc”)
String x = new String("xyz");
String y = "abc";
x = x + y;
我访问过很多网站,有人说这行代码创建了3个对象,有人说它创建了4个对象。我只是想知道在执行这行代码之后创建了多少个对象。新字符串(“xyz”)
当然会创建一个新实例。“abc”
和“xyz”
存储在类常量池中,x=x+y
在引擎盖下创建一个StringBuilder
,从而创建一个新字符串
,因此这里的字符串计数为4
编译器可能会用常量(
“xyzabc”
)替换x+y
),但是。在运行结束时,将有四个字符串
对象:
“xyz”
文本相对应的字符串
新字符串(“xyz”)
字符串
,对应于实习的“abc”
文本“xyz”+“abc”
真正的问题是将这些对象的一部分或全部归因于您的程序。可以合理地说,代码创建的
String
s只有两个或四个。即使总共有四个String
对象,对象1和3也不一定是由代码创建的,因为它们是常量池,因此它们是在代码的直接控制之外创建的。如果要测试实例,请运行此代码段并查看输出:
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
实例…我会说4,因为:
- +1
- +1
- +2
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
答案是4 由于您使用了
new
关键字,Java将在普通(非池)内存中创建一个新的字符串对象,x
将引用它。除此之外,文本“xyz”将放在字符串池中,该字符串池也是另一个字符串对象
因此,4个字符串对象是:
String x = "xyz";
String y = "abc";
x = x + y;
那么答案将是3
注:字符串#4位于非池内存中,因为字符串文字和通过计算常量表达式生成的字符串(见JLS§15.28)是唯一隐式插入的字符串
来源:SCJP Sun认证Java 6程序员(第6章第434页)这个答案是为了纠正一些其他答案所带来的误解: 例如: 不过,编译器可能会用常量(“xyzabc”)替换x+y。@Binkan Salaryman …和字符串对象4[对应于串联的字符串]也可以由编译器计算并转换为一个内部常量。@dasblinkenlight 这是不正确的。声明如下: 15.18.1.字符串连接运算符+ 字符串对象是新创建的(§12.5),除非表达式是常量表达式(§15.28) 为了限定为常量表达式,表达式中的变量名称必须为: 引用常量变量(§4.12.4)的简单名称(§6.5.6.1) 其中,“常量变量”定义为: 常量变量是使用常量表达式(§15.28)初始化的基元类型或字符串类型的最终变量 在本例中,
x
或y
都不是final
,因此它们不是常量变量。即使它们是final
,y
也不是常量变量,因为在初始化时使用了new
操作符
简而言之,Java编译器不允许将内部常量
“xyzabc”
用作串联表达式的结果
如果我在末尾添加以下语句:
System.out.println(x == "xyzabc");
假设编译器符合Java语言规范,它将始终打印
false
。答案是4
String x = new String("xyz");//First Object
String y = "abc";//Second Object
x = x + y;//Third, fourth Object
看看反编译类,您将看到所有内容:)答案应该是:
- 两个字符串(
和“xyz”
)只是对常量池中位置的引用,因此这些字符串不是由您的代码创建的“abc”
- 直接创建一个字符串(
)新字符串(“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
public java.lang.String方法(); 描述符:()Ljava/lang/String; 旗帜:ACC_PUBLIC 代码: 堆栈=3,局部变量=3,参数大小=1 0:new#2//class java/lang/String 3:dup 4:ldc#3//字符串xyz 6:invokespecial#4//方法java/lang/String.“:(Ljava/lang/String;)V 9:astore_1 10:ldc#5//字符串abc 12:astore_2 13:new#6//class java/lang/StringBuilder 16:dup 17:invokespecial#7//方法java/lang/StringBuilder。”“:()V 20:aload_1 21:invokevirtual#8//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 24:aload_2 25:invokevirtual#8//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder; 28:invokevirtual#9//方法java/lang/StringBuilder.toString:()Ljava/lang/String; 31:astore_1 32:alo
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)
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)
28: invokevirtual #36 // Method java/lang/StringBuilder.toString: ()Ljava/lang/String;;(fourth String Object is Created)
Line 1:String x = new String("xyz"); Line 2:String y = "abc"; Line 3:x = x + y;