今天在使用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是假的,为什么?
答案 0 :(得分:1)
我的期望是从所有s.o.p打印“true”,但是s3 == s4是假的,为什么?
编译器可以执行常量表达式内联。这意味着
String s1 = "abcd5";
String s2 = "abcd"+"5";
final String five = "5"; // final reference
String sa = "abcd" + five;
都是相同的(five
除外),编译器可以将所有这些表达式简化为"abcd5"
但是,如果编译器无法优化表达式,则会在运行时执行操作并创建新的String。这个新的String不是一个常量,它位于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[]
)
答案 1 :(得分:0)
您偶然发现了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
或<select ng-model="projectModel" ng-options="project as project.projectName">
<option>one</option>
<option>two</option>
<option>three</option>
<option>four</option>
<option>and so on... </option>
</select>
来确保一致的行为。
请注意,这些优化可能因编译器而异。