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

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.

вот рецепт для высококачественных равных метод:

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

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

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

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

  5. для примитивных полей, тип которых не float или double используйте == оператор сравнения; для полей ссылки на объект вызовите equals метод рекурсивно; для float поля, используйте статический!--33--> способ; и double поля, используйте Double.compare(double, double). Специальная обработка поплавковых и двойных полей обусловлена наличием Float.NaN,-0.0f и аналогичные двойные значения; в то время как вы могли бы сравнить 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, вы делаете семантические проверки сравнение тип и определение состояния объекты:

  • сам (тот же экземпляр)
  • сам (клон, или реконструированная копия)
  • другие объекты различных типов
  • другие объекты того же типа
  • 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) {
...
}