Java 赋值运算符执行

Java assignment operator execution

提问人:Sam 提问时间:6/21/2018 最后编辑:Sam 更新时间:6/28/2018 访问量:4336

问:

在 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)xyyx.equals(y)truexyfalse

Screenshot showing the source and that the output is "false"

这是怎么回事?

Java 字符串 等于 assignment-operator

评论

13赞 nits.kk 6/21/2018
我想你想看看结果x.equals( y = x )
1赞 Lino 6/21/2018
编译器可以内联和 ?xy
3赞 khelwood 6/21/2018
您是否假设在评估左侧的作业之前执行了右侧的作业?x = yx
0赞 Sam 6/21/2018
@khelwood是的,这是我的假设。它一定不能
1赞 Pedro A 6/23/2018
@nits.kk 我不这么认为。OP已经说过,他们明白评估结果为真。那么你所建议的行为就很明显了......x == (y = x)

答:

76赞 Joachim Sauer 6/21/2018 #1

首先:这是一个有趣的问题,但永远不应该出现在“真实代码”中,因为即使你知道它是如何工作的,分配给你在同一行中调用的变量也会令人困惑。

这里发生的事情是这 3 个步骤:

  1. 弄清楚要调用该方法的对象(即计算第一个对象,这将导致对字符串“hello”的引用)x
  2. 找出参数(即 evaluate ,它将更改为指向 String “goodbye” 并返回对该 String 的引用)x = yx
  3. 使用 #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 步。它加载 ,复制它(一次用于赋值,一次用于赋值表达式的返回值)并将其赋值给 。yx

第 #13 行调用第 #9 行中计算的结果和第 #10-12 行的结果。equals

评论

36赞 Bernhard Barker 6/22/2018
TL的;DR: => => => => .x.equals(x = y)"hello".equals(x = y)"hello".equals(x = "goodbye")"hello".equals("goodbye")false
8赞 Gaurang Tandon 6/22/2018
需要注意的重要一点是 . 的优先级高于 =
4赞 amalloy 6/23/2018
这与其说是关于优先级,不如说是关于评估顺序。无论如何,括号使优先级无关紧要。
5赞 Chetan Jadhav CD 6/21/2018 #2

x=y括号中的表达式是 现在,而外部的 x 中包含值(x=y)goodbyex.equalshello

评论

2赞 Gray 6/28/2018
这真的没有解释为什么会发生这种情况,也没有提供对其他人有帮助的额外细节。
0赞 Chetan Jadhav CD 6/29/2018
现在我大声朗读了它,我确实倾向于同意你的看法。其他答案非常冗长,所以要编辑它。
29赞 Keveloper 6/21/2018 #3

重要的是要记住,java 中的 a 是一个对象,因此是一个引用。当您致电时String

x.equals(...)

它正在检查当前引用的位置的值是否等于您传入的值。在内部,您正在更改引用的值,但您仍在使用原始引用(对“hello”的引用)进行调用。所以,现在你的代码正在比较“hello”是否等于“goodbye”,显然不是。在此之后,如果再次使用,将导致对与 y 相同的值的引用。xxequalsx

评论

0赞 Halayem Anis 6/21/2018
如果我理解你,这个:应该回来吗?"hello".equals((x = y))true
3赞 Keveloper 6/21/2018
不,因为 (x = y) 将返回 y 的值,即“再见”。因此,如果您执行“goodbye”.equals(x=y),则返回true
4赞 Randomness Slayer 6/21/2018 #4

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"

现在看来,很明显它应该以这种方式运行,但也很容易准确地看到每行中发生了什么,这是你应该努力争取的。

评论

2赞 Davis Herring 6/22/2018
回复:“总是”:有太多的露骨:你会建议把它写成三个语句吗?System.out.println("Bytes: "+1024*k);
0赞 Randomness Slayer 6/27/2018
@DavisHerring这是在调试的上下文中。如果您正在尝试调试该语句,那么是的,我绝对建议将此语句拆分为它的组件。一个语句用于乘法,另一个语句用于打印。它允许最大的灵活性。作为一般经验法则,您希望每行只做一件事。它使代码更具可读性,更易于调试。
38赞 Oleksandr Pyrohov 6/22/2018 #5

问得好!而 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.equalsx = y

因此,在将局部变量更改为引用字符串之前,将对字符串的引用记住为目标引用。因此,该方法被调用为带有参数 的目标对象,因此调用的结果是 。helloxgoodbyeequalshellogoodbyefalse

2赞 Vamsi 6/23/2018 #6

我认为这个问题通俗地说是.所以它返回 false。"hello".equals("goodbye")

-5赞 mmx 6/23/2018 #7

它正在查看 x.equals(将 x 分配给 y,始终返回 true) 所以基本上 x.equals(true)

评论

8赞 Sam 6/23/2018
这是不真实的,这不是评估作业的方式
2赞 Alishan 6/28/2018 #8

我已经在日食中尝试了你的问题,你的两个表达都是正确的。 1) x == (y = x) 计算结果为 true 这是真的,因为 x 的值分配给 y,即“你好”,然后 x 和 y 比较它们将 同样,所以结果为真

2) x.equal(x = y) 它是假的 因为 y 的值分配给 x 是再见的,那么 x 和 x 比较它们的值会不同,所以结果会是假的

1赞 Aadesk 6/28/2018 #9

在 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  

评论

1赞 Charlie Harding 7/1/2018
你真的运行过这个示例代码吗?正如问题所述,返回错误,与您的答案声称的相反。System.out.println(x.equals(x = y));