在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
,因为x
和y
现在应该共享相同的引用,但是我得到了false
。
这是怎么回事?
答案 0 :(得分:74)
首先:这是一个有趣的问题,但绝不应出现在“真实代码”中,因为即使您知道它的工作原理,在同一行中分配给您在同一行中调用的变量也会造成混淆。
这是这三个步骤:
x
,这将导致对字符串“ hello”的引用)x = y
,它将更改x
以指向字符串“再见”,并返回对该字符串的引用)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)