Java赋值运算符执行

时间:2018-06-21 13:40:42

标签: java string equals assignment-operator

在Java中,我知道赋值计算为正确的操作数的值,因此x == (y = x)之类的语句计算为true

但是,此代码输出false

public static void main(String[]args){
    String x = "hello";
    String y = "goodbye";
    System.out.println(x.equals(x = y));
}

这是为什么?以我的理解,它首先计算(x = y),该值将为x分配y的值,然后返回y的值。然后评估x.equals(y),其值应为true,因为xy现在应该共享相同的引用,但是我得到了false

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

这是怎么回事?

9 个答案:

答案 0 :(得分:74)

首先:这是一个有趣的问题,但绝不应出现在“真实代码”中,因为即使您知道它的工作原理,在同一行中分配给您在同一行中调用的变量也会造成混淆。

这是这三个步骤:

  1. 确定要在哪个对象上调用该方法(即,评估第一个x,这将导致对字符串“ hello”的引用)
  2. 确定参数(即评估x = y,它将更改x以指向字符串“再见”,并返回对该字符串的引用)
  3. 使用#2的结果作为参数,对#1的结果调用方法equals(分别引用字符串“ hello”和“再见”)。

查看为该方法生成的字节码可以很清楚地知道(假设您精通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

答案 1 :(得分:37)

好问题!而JLS有答案...

§15.12.4.1(示例15.12.4.1-2)。方法调用期间的评估顺序:

  

作为实例方法调用的一部分,有一个表达式   表示要调用的对象。这个表情似乎很充分   在该方法的任何参数表达式的任何部分之前进行求值   调用被评估。

所以,在:

String x = "hello";
String y = "goodbye";
System.out.println(x.equals(x = y));

在参数表达式x之前,首先计算.equals之前x = y的出现。

因此,在将本地变量hello更改为引用字符串x之前,对字符串goodbye的引用被记住为目标引用。结果,使用参数equals为目标对象hello调用了goodbye方法,因此调用的结果为false

答案 2 :(得分:27)

请记住,Java中的String是对象,因此是引用,这一点很重要。通话时

x.equals(...)

它正在检查x当前引用的位置的值是否等于您传递的值。在内部,您正在更改x引用,但您仍在使用原始参考(对“ hello”的参考)调用equals。因此,现在您的代码正在进行比较,以查看“ hello”是否等于“再见”,而事实显然并非如此。此后,如果再次使用x,将导致引用与y相同的值。

答案 3 :(得分:5)

括号中的

select user from ( select user=u.[user], weight= case a.product ='ServiceAgreement' then -1 else 0 end -- negative weight for undesirable agreement from users u join agreements a on u.AgreementId=a.AgreementId and a.product in ('ServiceAgreement','AggregationAgreement') -- we only have two agreements of interest here )t group by [user] having sum(weight)=0 -- should not be negative 表示表达式x=y现在为(x=y),而goodbye中的外部x保留值为x.equals

答案 4 :(得分:4)

Reimus给出了正确的答案,但我想详细说明。

在Java(和大多数语言)中,约定是变量在左侧,赋值在右侧。

让我们分解一下:

String x = "hello";
//x <- "hello"

String y = "goodbye";
//y <- "goodbye";

出于调试目的以及代码可读性的考虑,将行分割成一行只能做一件事始终是个好习惯。

System.out.println(x.equals(x = y)); //Compound statement

在这里,x.equals(...)在原始引用x或“ hello”上被调用,它被更新为第二个引用。

我将其写为(这将为您提供预期的答案):

x = y;
// x <- y = "goodbye"

boolean xEqualsX = x.equals(x);
// xEqualsX <- true

System.out.println(xEqualsX);
// "true"

现在看来,它应该以这种方式运行,但要弄清楚每行中到底发生了什么,这确实很容易,这是您应该争取的。

答案 5 :(得分:2)

我已经在日食中尝试过您的问题,您的两种表达方式都是正确的。 1)x ==(y = x)评估为true 这是正确的,因为x的值分配给y,这是'hello',然后x和y比较它们将 同样,结果将为真

2)x.equal(x = y)为假 因为y的值分配给x,所以x和x比较它们的值将不同,因此结果将为假

答案 6 :(得分:1)

我将这个问题以外行人的眼光看成"hello".equals("goodbye")。因此它返回false。

答案 7 :(得分:1)

在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  

答案 8 :(得分:-4)

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