В чем разница между == и equals() в Java?
Главное отличие: сравнение ссылок vs сравнение содержимого
Ключевое различие между == и equals() в Java заключается в том, что именно они сравнивают:
==— оператор сравнения ссылок. Он проверяет, указывают ли две переменные на один и тот же объект в памяти (одинаковый адрес).equals()— метод классаObject, который по умолчанию тоже сравнивает ссылки (как==). Но многие классы переопределяют его, чтобы сравнивать логическое содержимое объектов.
Почему в вашем примере a == b — true?
Это связано с интернированием строк (String interning). В Java есть пул строк (String pool). Когда вы создаете строку через литерал ("Привет"), JVM проверяет пул: если такая строка уже есть, она возвращает ссылку на существующий объект. Поэтому a и b ссылаются на один и тот же объект в пуле. == показывает true.
А c = new String("Привет") — это явное создание нового объекта в куче (heap), даже если в пуле такая строка уже есть. Поэтому a == c — false, так как это разные объекты.
Метод equals() у класса String переопределен и сравнивает именно последовательность символов. Поэтому a.equals(c) возвращает true — содержимое одинаковое.
Как это работает с другими объектами?
Для пользовательских классов, если вы не переопределили equals(), он будет работать как ==:
class Person {
String name;
Person(String name) { this.name = name; }
}
Person p1 = new Person("Иван");
Person p2 = new Person("Иван");
System.out.println(p1 == p2); // false — разные объекты
System.out.println(p1.equals(p2)); // false — equals из Object тоже сравнивает ссылки
Чтобы сравнивать логически, нужно переопределить equals() (и hashCode() вместе с ним):
class Person {
String name;
Person(String name) { this.name = name; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Person person = (Person) o;
return Objects.equals(name, person.name);
}
@Override
public int hashCode() {
return Objects.hash(name);
}
}
Person p1 = new Person("Иван");
Person p2 = new Person("Иван");
System.out.println(p1 == p2); // false
System.out.println(p1.equals(p2)); // true — теперь сравниваем по name
Практические правила
- Для примитивов (
int,double,booleanи др.) используйте только==— он сравнивает значения. - Для строк всегда используйте
equals(), если хотите сравнить текст.==может сработать случайно из-за интернирования, но это ненадежно. - Для объектов (включая обертки типа
Integer):==проверяет, один ли это объект;equals()— одинаковое ли содержимое (если метод переопределен). - Проверка на
null:==безопасен (можно писатьobj == null), аequals()вызоветNullPointerException, если объектnull. ИспользуйтеObjects.equals(a, b)для безопасного сравнения.
Итог
== — это про идентичность (один и тот же объект). equals() — про эквивалентность (логически равные объекты). Всегда смотрите документацию класса: переопределен ли equals(). Для String, оберток примитивов, коллекций — да. Для ваших классов — только если вы сами это сделали.
Дополнение: как не запутаться с Integer и другими обертками
Еще один частый источник ошибок — сравнение объектов-оберток, например Integer. Тут тоже есть "кэш" похожий на пул строк:
Integer x = 127;
Integer y = 127;
Integer a = 128;
Integer b = 128;
System.out.println(x == y); // true — из-за кэша Integer от -128 до 127
System.out.println(a == b); // false — выходят за пределы кэша
System.out.println(a.equals(b)); // true — правильный способ
Мораль: никогда не используйте == для сравнения оберток (Integer, Long, Boolean и т.д.), если вам не нужно проверить, что это буквально один и тот же объект. Всегда вызывайте .equals() или распаковывайте в примитив (a.intValue() == b.intValue()).
Также помните: для enum можно безопасно использовать ==, так как каждый экземпляр enum существует в единственном экземпляре (JVM гарантирует). Но для единообразия кода часто используют equals() — это тоже работает.
Ответов пока нет.
Войдите чтобы оставить ответ
Блоги