Как переопределить метод equals в java
Я пытаюсь переопределить метод equals в java. У меня есть класс людей, который в основном имеет 2 поля данных имя и возраст. Теперь я хочу переопределить метод equals, чтобы я мог проверить между объектами 2 человек.
мой код выглядит следующим образом
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
но когда я пишу возраст.равные(другие.возраст) это дает мне ошибку, поскольку метод equals может сравнивать только строку, а возраст-целое число.
пожалуйста, помогите мне исправить это.
спасибо заранее.
I используется = = оператор, как было предложено, и моя проблема решена. Большое спасибо всем, кто приложил усилия, чтобы помочь мне.
9 ответов:
//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 (!Person.class.isAssignableFrom(obj.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; } }выход:
run:
-- 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 секунд)
прежде всего: вы не переопределение
equals, вы перегрузка его.не видя фактического объявления
ageтрудно сказать, почему вы получаете ошибку.
Я не уверен в деталях, так как вы не опубликовали весь код, но:
- не забудьте переопределить
hashCode()а также- the
equalsметод должен иметьObject, а неPeopleв качестве типа аргумента. На данный момент вы перегружаете, а не переопределяете метод equals, который, вероятно, не то, что вы хотите, особенно учитывая, что вы проверяете его тип позже.- можно использовать
instanceofчтобы проверить, что это объект людей, напримерif (!(other instanceof People)) { result = false;}
equalsиспользуется для всех объектов, а не примитивы. Я думаю, вы имеете в виду возрастint(примитивный), в этом случае просто используйте==. Обратите внимание, что целое число (с большой буквы "I") является объектом, который следует сравнивать с равными.посмотреть какие вопросы следует учитывать при переопределении equals и hashCode в Java? для более подробной информации.
@Override public boolean equals(Object that){ if(this == that) return true;//if both of them points the same address in memory if(!(that instanceof People)) return false; // if "that" is not a People or a childclass People thatPeople = (People)that; // than we can cast it to People safely return this.name.equals(thatPeople.name) && this.age == thatPeople.age;// if they have the same name and same age, then the 2 objects are equal unless they're pointing to different memory adresses }
Так как я предполагаю
ageтипаint:public boolean equals(Object other){ boolean result; if((other == null) || (getClass() != other.getClass())){ result = false; } // end if else{ People otherPeople = (People)other; result = name.equals(otherPeople.name) && age == otherPeople.age; } // end else return result; } // end equals
пункт 10: подчиняйтесь генеральному контракту, когда переопределение равно
согласно эффективной Java, переопределение
equalsметод кажется простым, но есть много способов ошибиться, и последствия могут быть ужасными. Самый простой способ избежать проблем - не переопределятьequalsметод, в этом случае каждый экземпляр класса равен только самому себе. Это правильно, если любое из следующих условий применить:
каждый экземпляр класса по своей сути уникален. Это верно для таких классов, как поток, которые представляют активные сущности, а не значения. Реализация equals, предоставляемая Object, имеет точно правильное поведение для этих классов.
нет необходимости в том, чтобы класс предоставлял тест "логического равенства". например, java.утиль.регулярное выражение.Шаблон может быть переопределен равными чтобы проверить, представляют ли два экземпляра шаблона точно такое же регулярное выражение, но дизайнеры не думали, что клиенты будут нуждаться или хотят эту функциональность. В этих условиях реализация equals, унаследованная от объекта, является идеальной.
суперкласс уже переопределил equals, и поведение суперкласса подходит для этого класса. Например, большинство реализаций Set наследуют реализацию equals от AbstractSet, список реализаций из AbstractList и реализация карт из AbstractMap.
класс является частным или пакет-частный, и вы уверены, что его метод equals никогда не будет вызван. Если вы крайне не склонны к риску, вы можете переопределить метод equals, чтобы убедиться, что он не вызывается случайно:
The
equalsметод реализует отношение эквивалентности. Он имеет свойства:
Reflexive: для любого ненулевого ссылочного значения
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.вот рецепт для высококачественных равных метод:
использовать
==оператор, чтобы проверить, является ли аргумент ссылкой на этот объект. Если да, то верните true. Это просто оптимизация производительности, но это стоит сделать, если сравнение потенциально дорого.
использовать
instanceofоператор, чтобы проверить, если аргумент имеет неверный тип. Если нет, то вернуть false. Как правило, правильный тип-это класс, в котором происходит метод. Иногда это какой-то интерфейс реализовано этим классом. Используйте интерфейс, если класс реализует интерфейс, который уточняет контракт equals, чтобы разрешить сравнения между классами, реализующими интерфейс. Интерфейсы коллекции, такие как набор, список, карта и карта.Запись есть это свойство.
приведите аргумент к правильному типу. Поскольку этому приведению предшествовал тест instanceof, он гарантированно будет успешным.
для каждого "значимого" поля в классе, проверьте, соответствует ли это поле аргумента соответствующему полю данного объекта. Если все эти тесты успешно, возвращает true; в противном случае возвращает false. Если тип в шаге 2 является интерфейсом, необходимо получить доступ к полям аргумента с помощью методов интерфейса; если тип является классом, вы можете получить доступ к полям напрямую, в зависимости от их доступности.
для примитивных полей, тип которых не
floatилиdoubleиспользуйте==оператор сравнения; для полей ссылки на объект вызовитеequalsметод рекурсивно; дляfloatполя, используйте статический!--33--> способ; иdoubleполя, используйтеDouble.compare(double, double). Специальная обработка поплавковых и двойных полей обусловлена наличиемFloat.NaN,-0.0fи аналогичные двойные значения; в то время как вы могли бы сравнить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 }
при сравнении объектов в Java, вы делаете семантические проверки сравнение тип и определение состояния объекты:
- сам (тот же экземпляр)
- сам (клон, или реконструированная копия)
- другие объекты различных типов
- другие объекты того же типа
nullправила:
- симметрия:
a.equals(b) == b.equals(a)
equals()всегда даетtrueилиfalse, а неNullpointerException,ClassCastExceptionили любой другой throwableдля сравнения:
- тип проверки: оба экземпляра должны быть то же самое тип, то есть вы должны сравнить фактические классы для равенства. Это часто не правильно реализовано, когда разработчики используют
instanceofдля сравнения типов (который работает только до тех пор, пока нет подклассов, и нарушает правило симметрии, когдаA extends B -> a instanceof b != b instanceof a).- семантическая проверка состояния идентификации: убедитесь, что вы понимаете, по какому состоянию идентифицируются экземпляры. Лица могут быть идентифицированы по их номеру социального страхования, но не по цвету волос (может быть окрашен), имени (может быть изменен) или возрасту (меняется все время). Только с объектами value следует сравнивать полное состояние (все непереходные поля), в противном случае проверяйте только то, что идентифицирует экземпляр.
для
Personкласс:public boolean equals(Object obj) { // same instance if (obj == this) { return true; } // null if (obj == null) { return false; } // type if (!getClass().equals(obj.getClass())) { return false; } // cast and compare state Person other = (Person) obj; return Objects.equals(name, other.name) && Objects.equals(age, other.age); }многоразовые, общий класс полезности:
public final class Equals { private Equals() { // private constructor, no instances allowed } /** * Convenience equals implementation, does the object equality, null and type checking, and comparison of the identifying state * * @param instance object instance (where the equals() is implemented) * @param other other instance to compare to * @param stateAccessors stateAccessors for state to compare, optional * @param <T> instance type * @return true when equals, false otherwise */ public static <T> boolean as(T instance, Object other, Function<? super T, Object>... stateAccessors) { if (instance == null) { return other == null; } if (instance == other) { return true; } if (other == null) { return false; } if (!instance.getClass().equals(other.getClass())) { return false; } if (stateAccessors == null) { return true; } return Stream.of(stateAccessors).allMatch(s -> Objects.equals(s.apply(instance), s.apply((T) other))); } }для
Personкласс, используя этот служебный класс:public boolean equals(Object obj) { return Equals.as(this, obj, t -> t.name, t -> t.age); }
Если возраст int вы должны использовать == если это целочисленный объект, то вы можете использовать equals(). Вам также необходимо реализовать метод хэш-кода, если вы переопределяете equals. Детали договора доступны в javadoc объекта, а также на различных страницах в интернете.
метод equals определяет параметр метода типа Object и его возвращаемый тип является логическим.
Don’t change the name of the method, its return type, or the type of method parameterпри определении (переопределить) этот метод в вашем классе для сравнения двух объектов.
public boolean equals(Object anObject) { ... }