Выполнение оператора присваивания 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.



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



что здесь происходит?

728   9  

9 ответов:

прежде всего: это интересный вопрос, но он никогда не должен возникать в "реальном коде", поскольку назначение переменной, которую вы вызываете в той же строке, сбивает с толку, даже если вы знаете, как это работает.

что происходит, вот эти 3 шага:

  1. выяснить, какой объект для вызова метода (т. е. оценить первый x, это приведет к ссылке на строку "hello")
  2. выяснить параметры (т. е. оценить x = y, которым изменится x чтобы указать на строку "goodbye", а также вернуть ссылку на эту строку)
  3. вызов метода 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

Реймус дал правильный ответ, но я хотел бы уточнить.

в Java (и большинстве языков) соглашение переменная идет слева, назначение справа.

давайте разберем его:

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

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

для целей отладки, а также читабельности кода, это всегда хорошая практика, чтобы разделить ваши строки, так что они делают только одну вещь.

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

здесь x.equals(...) вызывается на исходную ссылку на x, или "Привет", он обновляется для вторая ссылка.

Я бы написал это как (и это даст вам ожидаемый ответ):

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 сравнивают их значение будет отличаться, поэтому результат будет ложным

Я вижу вопрос в непрофессиональных терминах как "hello".equals("goodbye"). Поэтому он возвращает false.

в java строка-это класс.

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  

Он видит, если x.равно (назначить x y, возвращает true всегда) так что в основном x. equals (true)

Comments

    Ничего не найдено.