Java 运行时字符串连接计算
根据JLS(15.28常量表达式),表达式仅包含:Java 运行时字符串连接计算,java,Java,根据JLS(15.28常量表达式),表达式仅包含: i)Literals of primitive type and literals of type String (§3.10.1, §3.10.2, §3.10.3, §3.10.4, §3.10.5) or ii)Simple names (§6.5.6.1) that refer to constant variables (§4.12.4). or iii)... 是一个常量表达式 现在strings1=“a”+“b”是一个常量表达式
i)Literals of primitive type and literals of type String (§3.10.1, §3.10.2, §3.10.3,
§3.10.4, §3.10.5)
or
ii)Simple names (§6.5.6.1) that refer to constant variables (§4.12.4).
or
iii)...
是一个常量表达式
现在strings1=“a”+“b”
是一个常量表达式,在编译时将计算为“ab”
所以s1=“ab”代码>
[1] 我说的对吗?根据上面的陈述,现在字符串池中有三个对象:-“a”、“b”、“ab”?
现在,
上述代码将被转换为s2=“a”+“b”代码>编译后
所以s2=“ab”代码>将自动存储在字符串池中
但是,
对于字符串s3=s+s1代码>,代码将被翻译为:
s3=new StringBuilder(String.valueOf(s)).append(s1).toString();
并将创建一个新的字符串对象
因此,s2==s3
将显示为false
这是否意味着在运行时使用StringBuilder计算的字符串连接结果不会存储在字符串池中,而是进入堆(池外)?
这是否意味着在运行时计算字符串连接的结果
使用StringBuilder不会存储在字符串池中,而是会
进入堆(池外)
对。这是正确的。它将在堆中创建新对象
根据上面的陈述,字符串池中有三个对象-“a”、“b”、“ab”?,我说的对吗
不,你错了。连接是在编译时执行的,只有“ab”对象将存储在字符串池中
这是否意味着在运行时使用StringBuilder计算的字符串连接结果不会存储在字符串池中,而是进入堆(池外)
是的,你在这一点上是正确的
总之,字符串文本和编译时常量字符串表达式的值将被存储(并存储在字符串池中)。其他字符串连接的结果将不会被保留。。。除非您显式调用String.intern()
。(而且你不应该这样做……因为插入字符串通常弊大于利。)
无论哪种方式,您都应该避免使用=
来比较字符串。来自JLS§15.18.1:
15.18.1。字符串连接运算符+
如果只有一个操作数表达式的类型为String,则为String
对另一个操作数执行转换(§5.1.11)以生成
在运行时使用字符串
字符串连接的结果是对字符串对象的引用
这是两个操作数字符串的串联。人物
左操作数的字符位于右操作数的字符之前
新创建的字符串中的操作数
字符串对象是新创建的(§12.5),除非表达式是
编译时常量表达式(§15.28)。
实现可以选择执行转换和串联
在一个步骤中避免创建然后丢弃中间
字符串对象。以提高重复字符串的性能
连接时,Java编译器可以使用StringBuffer类或
减少中间字符串对象数量的类似技术
通过表达式求值创建的
对于基元类型,实现还可以优化
通过直接从基元转换来创建包装器对象
键入一个字符串
所以
常量池(“ab”)中有一个对象。临时工不被保存
同样,常量池中也只有“ab”
新字符串是一个新的string
对象,除非显式插入,否则不会在池中
查看一些字节码很有意义:
String sa1 = "a"+ "b";
final String sb1 = "a";
final String sb2 = "b";
String sb3 = sb1 + sb2;
String sc1 = "a";
String sc2 = "b";
String sc3 = "a" + "b";
String sc4 = sc1 + sc2;
变成
Code:
0: ldc #2; //String ab
2: astore_0
3: ldc #2; //String ab
5: astore_3
6: ldc #3; //String a
8: astore 4
10: ldc #4; //String b
12: astore 5
14: ldc #2; //String ab
16: astore 6
18: new #5; //class java/lang/StringBuilder
21: dup
22: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
25: aload 4
27: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload 5
32: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
38: astore 7
40: return
代码:
0:ldc#2//字符串ab
2:astore_0
3:最不发达国家2//字符串ab
5:astore_3
6:最不发达国家3//串a
8:astore 4
10:最不发达国家4//b串
12:astore 5
14:最不发达国家2//字符串ab
16:astore 6
18:新#5//类java/lang/StringBuilder
21:dup
22:特别是#6//方法java/lang/StringBuilder。“”:()V
25:aload 4
27:invokevirtual#7//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30:aload 5
32:invokevirtual#7//方法java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35:invokevirtual#8//方法java/lang/StringBuilder.toString:()Ljava/lang/String;
38:astore 7
40:返回
您可以看到,在前两种情况下,“ab”直接从常量池加载。在第三个块中,我们得到了转换sc4=new StringBuilder().append(sc1).append(sc2).toString()
,它创建了一个新对象。是的,使用StringBuilder在运行时计算的字符串没有存储在字符串池中是正确的。因为:
有一个new
操作符(为堆中的对象分配新内存)
我们可以从代码中看到:
AbstractStringBuilder(整数容量){
值=新字符[容量];
}
堆中分配了一个新的字符数组引用。请注意,编译阶段的字符串池与程序运行时的字符串池不同。@Thorbjørn Ravn Andersen:这一点很好。你能给我一些链接或信息来源,让我了解你的观点的细节吗?如果专家认为这是个好主意,我建议添加一条关于只调用String.intern()
的注释。
String sa1 = "a"+ "b";
final String sb1 = "a";
final String sb2 = "b";
String sb3 = sb1 + sb2;
String sc1 = "a";
String sc2 = "b";
String sc3 = "a" + "b";
String sc4 = sc1 + sc2;
Code:
0: ldc #2; //String ab
2: astore_0
3: ldc #2; //String ab
5: astore_3
6: ldc #3; //String a
8: astore 4
10: ldc #4; //String b
12: astore 5
14: ldc #2; //String ab
16: astore 6
18: new #5; //class java/lang/StringBuilder
21: dup
22: invokespecial #6; //Method java/lang/StringBuilder."<init>":()V
25: aload 4
27: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
30: aload 5
32: invokevirtual #7; //Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
35: invokevirtual #8; //Method java/lang/StringBuilder.toString:()Ljava/lang/String;
38: astore 7
40: return