Как переопределить метод equals в Java
Я пытаюсь переопределить метод equals в Java. У меня есть класс, People
который в основном имеет 2 поля данных name
и age
. Теперь я хочу переопределить equals
метод, чтобы я мог проверять между объектами 2 People.
Мой код выглядит следующим образом
public boolean equals(People other){
boolean result;
if((other == null) || (getClass() != other.getClass())){
result = false;
} // end if
else{
People otherPeople = (People)other;
result = name.equals(other.name) && age.equals(other.age);
} // end else
return result;
} // end equals
Но когда я пишу, age.equals(other.age)
это выдает мне ошибку, поскольку метод equals может сравнивать только строку, а возраст - целое число.
Решение
Я использовал ==
оператор, как было предложено, и моя проблема решена.
Переведено автоматически
Ответ 1
//Written by K@stackoverflow
public class Main {
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
// TODO code application logic here
ArrayList<Person> people = new ArrayList<Person>();
people.add(new Person("Subash Adhikari", 28));
people.add(new Person("K", 28));
people.add(new Person("StackOverflow", 4));
people.add(new Person("Subash Adhikari", 28));
for (int i = 0; i < people.size() - 1; i++) {
for (int y = i + 1; y <= people.size() - 1; y++) {
boolean check = people.get(i).equals(people.get(y));
System.out.println("-- " + people.get(i).getName() + " - VS - " + people.get(y).getName());
System.out.println(check);
}
}
}
}
//written by K@stackoverflow
public class Person {
private String name;
private int age;
public Person(String name, int age){
this.name = name;
this.age = age;
}
@Override
public boolean equals(Object obj) {
if (obj == null) {
return false;
}
if (obj.getClass() != this.getClass()) {
return false;
}
final Person other = (Person) obj;
if ((this.name == null) ? (other.name != null) : !this.name.equals(other.name)) {
return false;
}
if (this.age != other.age) {
return false;
}
return true;
}
@Override
public int hashCode() {
int hash = 3;
hash = 53 * hash + (this.name != null ? this.name.hashCode() : 0);
hash = 53 * hash + this.age;
return hash;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
Вывод:
выполнить:
-- Subash Adhikari - VS - K false
-- Subash Adhikari - VS - StackOverflow false
-- Subash Adhikari - VS - Subash Adhikari true
-- K - VS - StackOverflow false
-- K - VS - Subash Adhikari false
-- StackOverflow - VS - Subash Adhikari false
- СБОРКА ВЫПОЛНЕНА УСПЕШНО (общее время: 0 секунд)
Ответ 2
Введение новой сигнатуры метода, которая изменяет типы параметров, называется перегрузкой:
public boolean equals(People other){
Здесь People
все иначе, чем Object
.
Когда сигнатура метода остается идентичной сигнатуре его суперкласса, это называется переопределением, а @Override
аннотация помогает различать их во время компиляции:
@Override
public boolean equals(Object other){
Не видя фактического объявления age
, трудно сказать, почему появляется ошибка.
Ответ 3
Я не уверен в деталях, поскольку вы опубликовали не весь код, но:
- не забудьте также переопределить
hashCode()
- в качестве типа аргумента
equals
метод должен иметьObject
, а неPeople
. В данный момент вы перегружаете, а не переопределяете метод equals, что, вероятно, не то, что вы хотите, особенно учитывая, что вы проверяете его тип позже. - вы можете использовать
instanceof
, чтобы проверить, что это объект People, напримерif (!(other instanceof People)) { result = false;}
equals
используется для всех объектов, но не для примитивов. Я думаю, вы имеете в виду, что age - этоint
(примитив), и в этом случае просто используйте==
. Обратите внимание, что целое число (с заглавной буквы 'I') - это объект, который следует сравнивать с equals.
Смотрите Какие проблемы следует учитывать при переопределении equals и хэш-кода в Java? для получения более подробной информации.
Ответ 4
Пункт 10: Соблюдайте общий контракт при переопределении equals
Согласно эффективной Java, переопределение
equals
метода кажется простым, но есть много способов сделать это неправильно, и последствия могут быть ужасными. Самый простой способ избежать проблем - не переопределятьequals
метод, и в этом случае каждый экземпляр класса равен только самому себе. Это правильно, если выполняется любое из следующих условий:
Каждый экземпляр класса по своей сути уникален. Это верно для таких классов, как Thread, которые представляют активные сущности, а не значения. Реализация equals, предоставляемая Object, имеет точно правильное поведение для этих классов.
Классу не нужно предоставлять тест на “логическое равенство”. Например, java.util.regex.Pattern мог переопределить equals, чтобы проверить, представляют ли два экземпляра шаблона в точности одно и то же регулярное выражение, но разработчики не подумали, что клиентам понадобится такая функциональность. В этих обстоятельствах реализация equals, унаследованная от Object, идеальна.
Суперкласс уже переопределил equals, и поведение суперкласса подходит для этого класса. Например, большинство реализаций Set наследуют свою реализацию equals от AbstractSet, реализации List - от AbstractList, а реализации Map - от AbstractMap.
Класс является закрытым или закрытым для пакета, и вы уверены, что его метод equals никогда не будет вызван. Если вы не склонны к риску, вы можете переопределить метод equals, чтобы убедиться, что он не будет вызван случайно:
equals
Метод реализует отношение эквивалентности. Он обладает следующими свойствами:
Рефлексивный: для любого ненулевого ссылочного значения
x
,x.equals(x)
должно возвращаться значение true.Симметричный: для любых ненулевых ссылочных значений
x
иy
,x.equals(y)
должно возвращать true тогда и только тогда, когда y.equals(x) возвращает true.Транзитивный: для любых ненулевых ссылочных значений
x
,y
,z
, еслиx.equals(y)
возвращаетtrue
иy.equals(z)
возвращаетtrue
, тоx.equals(z)
должен возвращатьtrue
.Согласовано: для любых ненулевых ссылочных значений
x
иy
множественные вызовыx.equals(y)
должны последовательно возвращатьtrue
или постоянно возвращатьfalse
, при условии, что информация, используемая в сравнениях equals, не изменена.Для любого ненулевого ссылочного значения
x
,x.equals(null)
должно возвращатьсяfalse
.
Вот рецепт высококачественного метода equals:
Используйте оператор
==
, чтобы проверить, является ли аргумент ссылкой на этот объект. Если да, верните true . Это всего лишь оптимизация производительности, но ее стоит выполнить, если сравнение потенциально дорогостоящее.Используйте оператор
instanceof
, чтобы проверить, имеет ли аргумент правильный тип. Если нет, верните false . Обычно правильный тип - это класс, в котором встречается метод. Иногда это какой-то интерфейс, реализованный этим классом. Используйте интерфейс, если класс реализует интерфейс, который уточняет контракт equals, чтобы разрешить сравнения между классами, реализующими интерфейс. Этим свойством обладают интерфейсы коллекций, такие как Set, List, Map и Map.Entry.Приведите аргумент к правильному типу. Поскольку этому приведению предшествовал тест instanceof, его успех гарантирован.
Для каждого “значимого” поля в классе проверьте, совпадает ли это поле аргумента с соответствующим полем этого объекта. Если все эти тесты завершились успешно, верните true; в противном случае верните false . Если тип на шаге 2 является интерфейсом, вы должны получить доступ к полям аргумента через методы интерфейса; если тип является классом, вы можете получить доступ к полям напрямую, в зависимости от их доступности.
Для примитивных полей, тип которых не является
float
ordouble
, используйте==
оператор для сравнений; для полей ссылки на объект вызывайтеequals
метод рекурсивно; дляfloat
полей используйте статическийFloat.compare(float, float)
метод; а дляdouble
полей используйтеDouble.compare(double, double)
. Специальная обработка полей float и double становится необходимой из-за существованияFloat.NaN
,-0.0f
и аналогичных значений double ; Хотя вы могли бы сравниватьfloat
иdouble
поля со статическими методамиFloat.equals
иDouble.equals
, это повлекло бы за собой автоматическую блокировку при каждом сравнении, что привело бы к снижению производительности. Дляarray
полей применяйте эти рекомендации к каждому элементу. Если каждый элемент в поле массива значим, используйте один изArrays.equals
методов.Некоторые поля ссылки на объект могут законно содержать
null
. Чтобы избежать возможностиNullPointerException
, проверьте такие поля на равенство с помощью статического методаObjects.equals(Object, Object)
.// Class with a typical equals method
public final class PhoneNumber {
private final short areaCode, prefix, lineNum;
public PhoneNumber(int areaCode, int prefix, int lineNum) {
this.areaCode = rangeCheck(areaCode, 999, "area code");
this.prefix = rangeCheck(prefix, 999, "prefix");
this.lineNum = rangeCheck(lineNum, 9999, "line num");
}
private static short rangeCheck(int val, int max, String arg) {
if (val < 0 || val > max)
throw new IllegalArgumentException(arg + ": " + val);
return (short) val;
}
@Override public boolean equals(Object o) {
if (o == this)
return true;
if (!(o instanceof PhoneNumber))
return false;
PhoneNumber pn = (PhoneNumber)o;
return pn.lineNum == lineNum && pn.prefix == prefix
&& pn.areaCode == areaCode;
}
... // Remainder omitted
}