我经常想知道,在最初为字符串赋值时,是否存在将字符串拆分为多行以提高可读性的性能成本.我知道字符串是不可变的,因此每次都需要创建一个新的字符串.此外,由于今天真正快速的硬件(除非你处于一些恶魔般的循环中),性能成本实际上是无关紧要的.例如:
String newString = "This is a really long long long long long" + " long long long long long long long long long long long long " + " long long long long long long long long long string for example.";
JVM或.Net的编译器和其他优化如何处理这个问题.它会创建一个字符串吗?或者它会创建1个字符串然后一个新的连接值,然后另一个连接值再次?
这是出于我自己的好奇心.
这可以保证C#规范与在单个文字中创建字符串相同,因为它是一个编译时常量.从C#3规范的第7.18节:
只要表达式满足上面列出的要求,就会在编译时计算表达式.即使表达式是包含非常量构造的较大表达式的子表达式,也是如此.
(有关"上面列出的要求"的详细信息,请参阅规范:)
Java语言规范在3.10.5节底部附近指定它:
由常量表达式计算的字符串(第15.28节)在编译时计算,然后将其视为文字.
实际上,在Java中,编译器会将其String
转换为常量.
class LongLongString { public LongLongString() { String newString = "This is a really long long long long long" + " long long long long long long long long long long long long " + " long long long long long long long long long string for example."; } public static void main(String[] args) { new LongLongString(); } }
编译成:
Compiled from "LongLongString.java" class LongLongString extends java.lang.Object{ public LongLongString(); Code: 0: aload_0 1: invokespecial #1; //Method java/lang/Object."":()V 4: ldc #2; //String This is a really long long long long long long long long long long long long long long long long long long long long long long long long long long string for example. 6: astore_1 7: return public static void main(java.lang.String[]); Code: 0: new #3; //class LongLongString 3: dup 4: invokespecial #4; //Method " ":()V 7: pop 8: return }
可以看出,第4行加载了一行,而不是String
加载了多个实例.
编辑:源文件是使用javac
版本1.6.0_06 编译的.看看Java语言规范,第三版(和Jon Skeet的答案中提到的相同部分),我无法找到关于编译器是否应该将多行连接String
成单个的任何参考String
,所以这种行为可能是编译器实现特定的.
自己测试一下.在C#代码中(等效的Java也可以):
string x = "A" + "B" + "C"; string y = "ABC"; bool same = object.ReferenceEquals(x, y); // true
你会看到结果是true
.
顺便说一句,您将看到该字符串也在运行时的字符串池中实现:
bool interned = object.ReferenceEquals(x, string.Intern(x)); // true
没有性能权衡.编译器的优化会将其合并为单个字符串(至少在Java中).