为什么是这样?
String str1 = "one";
String str2 = "two";
System.out.println(str1.equals(str1 = str2)); // false, doesn't assignment of ref. to string object memory location happens after???
System.out.println(str1.equals(str1 = str2)); // true, same statement
Run Code Online (Sandbox Code Playgroud)
我在模拟面试中被问到这个问题,但我仍然不明白。
Bor*_*ris 30
我认为答案在Java 语言规范中,它描述了第 15.7 点中的评估顺序。通常这是从左到右完成的。在您的情况下,评估将是
str1.equals
)->"one"
str1 = str2
)->"two"
str1 = str2
) -> str1 现在是"two"
str1 = str2
是"two"
,但请记住,对于此语句,str1 已在第一步中加载。它不会再次加载。"one"
使用参数"two"
-> false调用 equals on (已加载,见上文)您还可以查看反编译的 Java 代码(javap -c ClassName
在您的类路径上运行),它也会向您显示以下顺序:
0: ldc #7 // String one
2: astore_1
3: ldc #9 // String two
5: astore_2
[...]
9: aload_1 // <-- loads the value of str1
10: aload_2 // <-- loads the value of str2
11: dup
12: astore_1 // <-- stores to str1
13: invokevirtual #17 // <-- invokes equals
Run Code Online (Sandbox Code Playgroud)
这不会做的是在存储到 str1 后再次加载它的值。
语言规范有更多关于边缘情况及其处理方式的示例(例如“如果函数的参数之一是引发异常的函数会发生什么情况)。
Java 规范15.12.4。方法调用的运行时评估管理这一点。它指出; “在运行时,方法调用需要五个步骤。首先,可以计算目标引用。其次,评估参数表达式。......”
所以我们首先计算目标,然后评估参数。
您示例中的目标表达式是str1
,它在评估参数之前将评估为特定的字符串对象。所以我们调用Equals
那个对象的方法。在这一点上,我们不再关心变量 str1,并且在评估参数时更改此变量指向的对象这一事实无关紧要。
在我的第一个答案中,我说这些行中的每一行都可以分解为 3 个单独的语句:赋值、equals
、println
。然而,这产生了不同的字节码,因此,我的说法是错误的。
这是内部发生的事情,使用 OP 代码段的第 3 行生成的字节码进行演示:
0: ldc #2 // String one
2: astore_1
3: ldc #3 // String two
5: astore_2
6: getstatic #4 // Field java/lang/System.out:Ljava/io/PrintStream;
9: aload_1
10: aload_2
11: dup
12: astore_1
13: invokevirtual #5 // Method java/lang/String.equals:(Ljava/lang/Object;)Z
16: invokevirtual #6 // Method java/io/PrintStream.println:(Z)V
Run Code Online (Sandbox Code Playgroud)
这里值得注意的部分是aload_1
in 偏移量 9 存储str1
了堆栈上的初始值。偏移量 10、11 和 12 然后执行重新分配,但堆栈中的值保持不变,因此仍包含旧引用。
这就是 str1.equals(str1=str2) 为 false 的原因。
我想这是为什么应该避免内联分配的主要例子。
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
....
}
Run Code Online (Sandbox Code Playgroud)
简短回答:在第一个语句中this
保留“one”,因此对 的“旧版本”进行操作str1
,即使对象同时发生变化。
归档时间: |
|
查看次数: |
1222 次 |
最近记录: |