Вопрос-ответ

How to override equals method in Java

Как переопределить метод 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:


  1. Используйте оператор ==, чтобы проверить, является ли аргумент ссылкой на этот объект. Если да, верните true . Это всего лишь оптимизация производительности, но ее стоит выполнить, если сравнение потенциально дорогостоящее.


  2. Используйте оператор instanceof, чтобы проверить, имеет ли аргумент правильный тип. Если нет, верните false . Обычно правильный тип - это класс, в котором встречается метод. Иногда это какой-то интерфейс, реализованный этим классом. Используйте интерфейс, если класс реализует интерфейс, который уточняет контракт equals, чтобы разрешить сравнения между классами, реализующими интерфейс. Этим свойством обладают интерфейсы коллекций, такие как Set, List, Map и Map.Entry.


  3. Приведите аргумент к правильному типу. Поскольку этому приведению предшествовал тест instanceof, его успех гарантирован.


  4. Для каждого “значимого” поля в классе проверьте, совпадает ли это поле аргумента с соответствующим полем этого объекта. Если все эти тесты завершились успешно, верните true; в противном случае верните false . Если тип на шаге 2 является интерфейсом, вы должны получить доступ к полям аргумента через методы интерфейса; если тип является классом, вы можете получить доступ к полям напрямую, в зависимости от их доступности.


  5. Для примитивных полей, тип которых не является float or double, используйте == оператор для сравнений; для полей ссылки на объект вызывайте 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 методов.


  6. Некоторые поля ссылки на объект могут законно содержать 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

    }

java