提问人:Sam 提问时间:6/21/2018 最后编辑:Sam 更新时间:6/28/2018 访问量:4336
Java 赋值运算符执行
Java assignment operator execution
问:
在 Java 中,我知道赋值的计算结果为正确的操作数的值,因此像 Evaluate 为 .x == (y = x)
true
但是,此代码输出 .false
public static void main(String[]args){
String x = "hello";
String y = "goodbye";
System.out.println(x.equals(x = y));
}
为什么会这样?在我的理解中,它首先计算 ,它赋值 ,然后返回 的值。然后进行评估,这应该是 since 并且现在应该共享相同的引用,但相反,我得到.(x = y)
x
y
y
x.equals(y)
true
x
y
false
这是怎么回事?
答:
首先:这是一个有趣的问题,但永远不应该出现在“真实代码”中,因为即使你知道它是如何工作的,分配给你在同一行中调用的变量也会令人困惑。
这里发生的事情是这 3 个步骤:
- 弄清楚要调用该方法的对象(即计算第一个对象,这将导致对字符串“hello”的引用)
x
- 找出参数(即 evaluate ,它将更改为指向 String “goodbye” 并返回对该 String 的引用)
x = y
x
- 使用 #2 的结果作为参数(分别是对字符串“hello”和“goodbye”的引用)对 #1 的结果调用方法。
equals
查看为该方法生成的字节码就很清楚了(假设您精通 Java 字节码):
0: ldc #2 // String hello
2: astore_1
3: ldc #3 // String goodbye
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
19: return
第 #9 行是上面的第 1 步(即计算并记住该值)。x
第 #10-12 行是第 2 步。它加载 ,复制它(一次用于赋值,一次用于赋值表达式的返回值)并将其赋值给 。y
x
第 #13 行调用第 #9 行中计算的结果和第 #10-12 行的结果。equals
评论
x.equals(x = y)
"hello".equals(x = y)
"hello".equals(x = "goodbye")
"hello".equals("goodbye")
false
.
的优先级高于 =
。
x=y
括号中的表达式是 现在,而外部的 x 中包含值(x=y)
goodbye
x.equals
hello
评论
重要的是要记住,java 中的 a 是一个对象,因此是一个引用。当您致电时String
x.equals(...)
它正在检查当前引用的位置的值是否等于您传入的值。在内部,您正在更改引用的值,但您仍在使用原始引用(对“hello”的引用)进行调用。所以,现在你的代码正在比较“hello”是否等于“goodbye”,显然不是。在此之后,如果再次使用,将导致对与 y 相同的值的引用。x
x
equals
x
评论
"hello".equals((x = y))
true
Reimus 给出了正确的答案,但我想详细说明一下。
在 Java(和大多数语言)中,约定是变量在左边,赋值在右边。
让我们分解一下:
String x = "hello";
//x <- "hello"
String y = "goodbye";
//y <- "goodbye";
出于调试目的和代码可读性,最好拆分行,以便它们只做一件事。
System.out.println(x.equals(x = y)); //Compound statement
在这里,在对 x 的原始引用或“hello”上调用,它为第二个引用进行了更新。x.equals(...)
我会把它写成(这会给你你预期的答案):
x = y;
// x <- y = "goodbye"
boolean xEqualsX = x.equals(x);
// xEqualsX <- true
System.out.println(xEqualsX);
// "true"
现在看来,很明显它应该以这种方式运行,但也很容易准确地看到每行中发生了什么,这是你应该努力争取的。
评论
System.out.println("Bytes: "+1024*k);
问得好!而 JLS 有答案......
§15.12.4.1(例15.12.4.1-2)。方法调用期间的评估顺序:
作为实例方法调用的一部分,有一个表达式 表示要调用的对象。这个表达似乎是完全的 在方法的任何参数表达式的任何部分之前计算 评估调用。
所以,在:
String x = "hello";
String y = "goodbye";
System.out.println(x.equals(x = y));
首先计算 before 的出现,在参数表达式之前。x
.equals
x = y
因此,在将局部变量更改为引用字符串之前,将对字符串的引用记住为目标引用。因此,该方法被调用为带有参数 的目标对象,因此调用的结果是 。hello
x
goodbye
equals
hello
goodbye
false
我认为这个问题通俗地说是.所以它返回 false。"hello".equals("goodbye")
它正在查看 x.equals(将 x 分配给 y,始终返回 true) 所以基本上 x.equals(true)
评论
我已经在日食中尝试了你的问题,你的两个表达都是正确的。 1) x == (y = x) 计算结果为 true 这是真的,因为 x 的值分配给 y,即“你好”,然后 x 和 y 比较它们将 同样,所以结果为真
2) x.equal(x = y) 它是假的 因为 y 的值分配给 x 是再见的,那么 x 和 x 比较它们的值会不同,所以结果会是假的
在 java 中,String 是一个类。
String x = "hello";
String y = "goodbye";
是一个两个不同的 String,它指的是两个不同的值,它们不相同 如果你比较
System.out.println(x.equals(x = y));
//this compare value (hello and goodbye) return true
System.out.println(x == (y = x));
// this compare reference of an object (x and y) return false
评论
System.out.println(x.equals(x = y));
评论
x.equals( y = x )
x
y
x = y
x
x == (y = x)