Разница между == и .equals в Java. - PullRequest
3 голосов
/ 29 июля 2011

Я знаю, что это было покрыто, но я видел противоречивые аргументы здесь на SO.

Итак, если у меня есть:

String a = "apple2e";
String b = "apple2e";

System.out.println("a==b? " + a == b);

Я получаю ЛОЖЬ .

Насколько я понимаю, это потому, что a и b - это две разные ссылки на один и тот же объект (apple2e).

Так что я хотел бы что-то вроде:

a (reference_id 123) ------
                           ---------  "apple2e"
b (reference_id 456) ------

Теперь, если я просто хочу сравнить содержимое двух строк, я бы использовал a.equals(b)

Означает ли это, что JVM просто возвращает, если две ссылки указывают на один и тот же объект? Значит, на самом деле не проводится посимвольное сравнение?

Спасибо

EDIT

Держи телефоны. Спасибо delnan за указание + приоритета !!!

Когда я изменяю его на:

System.out.println(a == b);

Я действительно получаю true.

Это имеет больше смысла.

РЕДАКТИРОВАТЬ 2

Не могу поверить, что не понял этого. лол

Я делал:

"a==b? " + a == b

Что переводится как

"a==b? apple2e" == "apple2e"

Не удивительно, что это было ложно !!

Ответы [ 7 ]

6 голосов
/ 29 июля 2011

Ваш первый пример на самом деле верен. Выражение в println просто не делает то, что вы имели в виду.

String a = "apple2e";
String b = "apple2e";

System.out.println("a==b? " + (a == b));

Напечатает a==b? true Обратите внимание на все важные группировки!

Вы правы, что a и b - две разные ссылки на один и тот же объект. Именно поэтому == возвращает true, когда вы тестируете это! == проверяет, указывают ли два разных указателя на одно и то же место в памяти. И a, и b являются ссылками на одно и то же место в памяти, где хранится внутренняя строка apple2e времени компиляции.

Теперь, если вы сделали это

String a = new String("apple2e");
String b = new String("apple2e");

System.out.println("a==b? " + (a == b));

На самом деле он напечатает a==b? false. Поскольку вы сделали два разных объекта в памяти, a и b указывают на разные места.

6 голосов
/ 29 июля 2011

Насколько я понимаю, это потому, что a и b - это две разные ссылки на один и тот же объект (apple2e).

Из-за интернирования строк и только из-за интернирования строк a и b являются разными ссылками на один и тот же String объект.


К сожалению, ваш код не делает то, что вы думаете, что он делает. Попробуйте это:

String a = "apple2e";
String b = "apple2e";

System.out.println("a==b? " + a == b);    // "false"
System.out.println("a==b? " + (a == b));  // "a==b? true"

Java автоматически интернирует все строковые литералы. Это , поэтому второй sysout печатает, что он делает. Первый sysout печатает только "false", потому что конкатенация строк (+) имеет более высокий приоритет, чем ==, поэтому это эквивалентно этому:

System.out.println("a==b? apple2e" == "apple2e");

Не думаю, что вы это хотели проверить!

Это, с другой стороны, даст вам два отдельных String экземпляра:

String a = new String("apple2e");
String b = new String("apple2e");

System.out.println("a==b? " + (a == b));  // "a==b? false"

Который схематически будет выглядеть

a (reference_id 123) ---------------  "apple2e"

b (reference_id 456) ---------------  "apple2e"

и может быть уменьшен до исходной ситуации с помощью String#intern():

String a = new String("apple2e").intern();
String b = new String("apple2e").intern();

System.out.println("a==b? " + (a == b));  // "a==b? true"
* * +1036 например,
a (reference_id 123) ------+
                           +---------  "apple2e"
b (reference_id 456) ------+
5 голосов
/ 29 июля 2011

'a' и 'b' - это одна и та же ссылка, проблема в том, что вы не сравниваете a и b. Вы должны ожидать

a==b? false

но вы просто получаете

false

Это потому, что + имеет приоритет над ==, поэтому у вас есть

System.out.println(("a==b? " + a) == b);

Точно так же вы ожидаете, что следующее выведет true.

System.out.println(1 + 2 == 3);

Что вам нужно, это

System.out.println("a==b? " + (a == b));
4 голосов
/ 29 июля 2011

a == b проверяет, указывают ли два объекта на один и тот же объект в памяти. Поскольку они не совпадают, даже если их внутренности одинаковы, a == b будет ложным. 1 == 1 будет истинно, потому что целые числа являются примитивными переменными, а строки на самом деле являются объектами.

a.equals (b) - это метод экземпляра, который внутренне проверяет, имеют ли две строки одинаковые символы.

Если вы сделали:

String a = "hello";
String b = a;

Тогда a == b будет истинным.

1 голос
/ 29 июля 2011

Если вы переключитесь на следующее: System.out.println("a==b? " + (a == b));

Вы получите a==b? true

То, что происходит здесь, заключается в том, что a и b оба указывают на внутренний кэш строк, который поддерживаетсякласс String.

Вот реализация String.equals ()

public boolean equals(Object anObject) {
if (this == anObject) {
    return true;
}
if (anObject instanceof String) {
    String anotherString = (String)anObject;
    int n = count;
    if (n == anotherString.count) {
    char v1[] = value;
    char v2[] = anotherString.value;
    int i = offset;
    int j = anotherString.offset;
    while (n-- != 0) {
        if (v1[i++] != v2[j++])
        return false;
    }
    return true;
    }
}
return false;
}

anObject должна быть String, чтобы возвращать true, если это ссылка натот же объект, то он немедленно возвращает истину.В противном случае, как вы можете видеть, выполняется сравнение символов.

1 голос
/ 29 июля 2011

a и b - две разные ссылки на один и тот же объект - вероятно,

"a==b? " + a

вычисляется как строка "a == b? Apple2e", которая определенно не совпадает (либо ==, либо равно) как строка "apple2e"

Итак, ваш код:

System.out.println("a==b? " + a == b);

просто проверяет, совпадает ли "a == b? apple2e" с "apple2e", но это не так (независимо от того, как вы определяете же)

1 голос
/ 29 июля 2011

apple2e не является объектом. Это значение, указанное в ссылке.

String a = "apple2e";
String b = "apple2e";

Здесь a, b - это объекты (ссылки) на значение apple2e, хранящиеся в двух разных местах.

...