Выполнение оператора присваивания Java
в 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
.
что здесь происходит?
9 ответов
прежде всего: это интересный вопрос, но он никогда не должен возникать в "реальном коде", так как назначение переменной, которую вы вызываете в той же строке, сбивает с толку, даже если вы знаете, как это работает.
что происходит, вот эти 3 шага:
- выяснить, какой объект для вызова метода (т. е. оценить первый
x
, это приведет к ссылке на строку "hello") - выяснить параметры (т. е. оценить
x = y
, которым изменитсяx
указать на строку "goodbye", а также вернуть ссылку на эту строку) - вызов метода
equals
о результате #1, используя результат #2 в качестве параметра (который будет ссылками на строки "hello" и "goodbye" соответственно).
глядя на байтовый код, созданный для этого метода, становится ясно (при условии, что вы свободно владеете байт-кодом 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 вызывает equals
на результат, вычисленный в строке #9 и результат строк #10-12.
хороший вопрос! И у 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
.
важно помнить, что a String
в java является объектом и, следовательно, ссылкой. Когда вы звоните
x.equals(...)
это проверка, если значение в этом месте имеются ссылки x
равно тому,что вы передаете. Внутри, вы меняете значение x
и ссылка, но вы все еще звоните equals
С оригинал ссылка (ссылка на "привет"). Итак, прямо сейчас ваш код сравнивает, чтобы увидеть, если "привет" равнозначно "до свидания", чего явно нет. После этого пункта, если вы используете x
опять же, это приведет ссылку на то же значение, что и y.
x=y
в скобках означает, что выражение (x=y)
теперь goodbye
, в то время как внешний x в x.equals
имеет значение hello
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"
теперь кажется очевидным, что он должен вести себя таким образом, но также очень легко увидеть, что именно происходит в каждой строке, к чему вы должны стремиться.
Я пробовал ваш вопрос в eclipse, ваше оба выражения верны. 1) x = = (y = x) оценить в true это верно, потому что значение x присваивается y, которое является "привет", тогда x и y сравнивают они будут то же самое так результат будет true
2) x.равно (x = y) это ложь поскольку значение y присваивается x, которое прощается, то x и X сравнивают их значение будет отличаться, поэтому результат будет false
Я вижу вопрос в терминах непрофессионала как "hello".equals("goodbye")
. Поэтому он возвращает false.
в java String является классом.
String x = "hello";
String y = "goodbye";
- это две разные строки, которые ссылаются на два разных значения, которые не совпадают а если сравнить
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