String + String vs String + String 从方法返回
String + String vs String + String returned from method
今天在处理 String 时,我遇到了一种我以前不知道的行为。我无法理解内部发生的事情。
public String returnVal(){
return "5";
}
String s1 = "abcd5";
String s2 = "abcd"+"5";
String s3 = "abcd5";
String s4 = "abcd"+returnVal();
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(s3 == s4);
System.out.println(s3.equals(s4));
我的期望是从所有 s.o.p 打印 "true",但 s3 == s4 是假的,为什么?
My expectation is printing "true" from all s.o.p's but s3 == s4 is false, why?
编译器可以进行常量表达式内联。这意味着
String s1 = "abcd5";
String s2 = "abcd"+"5";
final String five = "5"; // final reference
String sa = "abcd" + five;
都是一样的(除了five
),编译器可以将所有这些表达式简化为"abcd5"
但是,如果编译器无法优化表达式,则在 运行 时执行操作并创建一个新的 String。这个新字符串不是字符串文字池中的常量(因为它不是字节码中的文字)
String s4 = "abcd" + returnVal(); // not inlined by the compiler.
String f5 = "5"; // not a final reference.
String sb = "abcd" + f5; // evaluated at runtime
它们每次 运行(以及新的 StringBuilder
和 char[]
s)时都会创建新字符串
您偶然发现了 Java 编译器如何优化 String
的复杂性。
假设我有这个程序:
String a = "abc";
String b = "abc";
这里编译器可以将a
和b
初始化为同一个String
实例。这需要 a == b
和 a.equals(b)
.
这里我们也得到了相同的行为:
String a = "abc";
String b = "ab" + "c";
这是因为 "ab" + "c"
可以在编译时计算为 "abc"
,这又可以与 a
共享一个实例。
调用函数的表达式无法使用此技术:
String a = "abc";
String b = "ab" + functionThatReturnsC();
这是因为 functionThatReturnsC
可能会产生无法在编译时解决的副作用。
你的 returnVal
案例很有趣。由于它是常量,因此可以内联,在这种情况下可以应用编译时实例共享。似乎编译器实现者决定不支持这个。
这个问题暴露了 Java 的弱点。由于我们无法覆盖 =
,程序员无法实现自定义值类型。因此,您应该始终使用 equals
或 Objects.equals
来确保一致的行为。
请注意,这些优化可能因编译器而异。
今天在处理 String 时,我遇到了一种我以前不知道的行为。我无法理解内部发生的事情。
public String returnVal(){
return "5";
}
String s1 = "abcd5";
String s2 = "abcd"+"5";
String s3 = "abcd5";
String s4 = "abcd"+returnVal();
System.out.println(s1 == s2);
System.out.println(s1.equals(s2));
System.out.println(s3 == s4);
System.out.println(s3.equals(s4));
我的期望是从所有 s.o.p 打印 "true",但 s3 == s4 是假的,为什么?
My expectation is printing "true" from all s.o.p's but s3 == s4 is false, why?
编译器可以进行常量表达式内联。这意味着
String s1 = "abcd5";
String s2 = "abcd"+"5";
final String five = "5"; // final reference
String sa = "abcd" + five;
都是一样的(除了five
),编译器可以将所有这些表达式简化为"abcd5"
但是,如果编译器无法优化表达式,则在 运行 时执行操作并创建一个新的 String。这个新字符串不是字符串文字池中的常量(因为它不是字节码中的文字)
String s4 = "abcd" + returnVal(); // not inlined by the compiler.
String f5 = "5"; // not a final reference.
String sb = "abcd" + f5; // evaluated at runtime
它们每次 运行(以及新的 StringBuilder
和 char[]
s)时都会创建新字符串
您偶然发现了 Java 编译器如何优化 String
的复杂性。
假设我有这个程序:
String a = "abc";
String b = "abc";
这里编译器可以将a
和b
初始化为同一个String
实例。这需要 a == b
和 a.equals(b)
.
这里我们也得到了相同的行为:
String a = "abc";
String b = "ab" + "c";
这是因为 "ab" + "c"
可以在编译时计算为 "abc"
,这又可以与 a
共享一个实例。
调用函数的表达式无法使用此技术:
String a = "abc";
String b = "ab" + functionThatReturnsC();
这是因为 functionThatReturnsC
可能会产生无法在编译时解决的副作用。
你的 returnVal
案例很有趣。由于它是常量,因此可以内联,在这种情况下可以应用编译时实例共享。似乎编译器实现者决定不支持这个。
这个问题暴露了 Java 的弱点。由于我们无法覆盖 =
,程序员无法实现自定义值类型。因此,您应该始终使用 equals
或 Objects.equals
来确保一致的行为。
请注意,这些优化可能因编译器而异。