JavaRush /Blog Java /Random-PL /Przeciążanie metod równości() i hashCode() w Javie
Coder
Poziom 17

Przeciążanie metod równości() i hashCode() w Javie

Opublikowano w grupie Random-PL

Zastępowanie metod równości() i hashCode() w Javie

Equalsi hashCodesą podstawowymi metodami zadeklarowanymi w klasie Objecti zawartymi w standardowych bibliotekach Java. Przeciążanie metod równości() i hashCode() w Javie - 1Metoda еquals()służy do porównywania obiektów i hashCodegenerowania kodu całkowitego dla obiektu. Metody te są szeroko stosowane w standardowych bibliotekach Java podczas wstawiania i pobierania obiektów w plikach HashMap. Metodę tę equalstosuje się również w celu zapewnienia, że ​​w HashSetinnych Setimplementacjach przechowywane są tylko unikalne obiekty, a także we wszystkich innych przypadkach, gdy zachodzi potrzeba porównania obiektów. Domyślna implementacja metody equals()w klasie java.lang.Objectporównuje odniesienia do adresów pamięci przechowywanych przez zmienne i zwraca truetylko wtedy, gdy adresy są zgodne, innymi słowy zmienne odnoszą się do tego samego obiektu. Java zaleca zastąpienie metod equals()i hashCode(), jeśli oczekujesz, że porównanie zostanie wykonane zgodnie z logiką naturalną lub logiką biznesową. Wiele klas w standardowych bibliotekach Java zastępuje je, na przykład klasa Stringzastępuje je equalsw taki sposób, że zwraca, truejeśli zawartość dwóch porównywanych obiektów jest taka sama. Klasa opakowania zastępuje Integermetodę equalw celu przeprowadzenia porównania numerycznego i tak dalej. Ponieważ Java HashMaprównież opiera się na metodach i do porównywania ich i , Java oferuje następujące reguły zastępowania tych metod: HashTableequals()hashCode()keyvalues
  1. Zwrotność: Obiekt musi być równy sobie.
  2. Symetryczny: jeśli a.equals(b)zwróci true, to b.equals(a)musi również wrócić true.
  3. Przechodniość: jeśli a.equals(b)zwraca truei b.equals(c)zwraca również true, to c.equals(a)musi również powrócić true.
  4. Spójność: Powtarzające się wywołania metody equals()muszą zwracać tę samą wartość, o ile niektóre wartości właściwości obiektu nie ulegną zmianie. Oznacza to, że jeśli dwa obiekty w Javie są równe, to będą takie same, o ile ich właściwości pozostaną niezmienione.
  5. Porównanie null: Należy sprawdzić obiekt null. Jeśli obiekt jest równy null, to metoda powinna zwrócić false, a nie NullPointerException. Na przykład a.equals(null)powinien wrócić false.

Umowa pomiędzy równymi i hashCode w Javie

  1. Jeżeli obiekty w wynikach wykonania metody są sobie równe equals, to hashcodemuszą być takie same.
  2. Jeśli obiekty nie są równe w wynikach wykonania metody equals, to hashcodemogą być takie same lub różne. Aby jednak poprawić wydajność, lepiej jest, aby różne obiekty zwracały różne kody.

Jak zastąpić metodę równości w Javie

  1. @Override
    public boolean equals(Object obj) {
    /*1. Sprawdzać*/if (obj == this) {
    /*i powrót */ return true;
             }
  2. Sprawdź obiekt pod kątem null, a także sprawdź, czy obiekty są tego samego typu. Nie sprawdzaj, instanceofponieważ zwróci to truedla podklas i będzie działać poprawnie tylko wtedy, gdy twoja klasa zostanie zadeklarowana jako immutable. Możesz użyć getClass();

    if (obj == null || obj.getClass() != this.getClass()) {
                return false;
    }
  3. Объявите переменную типа, который вы сравниваете, и приведите obj к этому типу. Потом сравнивайте каждый атрибут типа начиная с численных атрибутов (если имеются) потому что численные атрибуты проверяются быстрей. Сравнивайте атрибуты с помощью операторов И и ИЛИ (так называемые short-circuit logical operators) для объединения проверок с другими атрибутами.

    Person guest = (Person) obj;
            return id == guest.id && (firstName == guest.firstName ||
                (firstName != null && firstName.equals(guest.getFirstName())))
                    && (lastName == guest.lastName || (lastName != null &&                      lastName .equals(guest.getLastName())));
    }
Полный пример переопределения метода equals в Java
/** * Person class with equals and hashcode implementation in Java * @author Javin Paul */
public class Person {
    private int id;
    private String firstName;
    private String lastName;

    public int getId() { return id; }
    public void setId(int id) { this.id = id;}

    public String getFirstName() { return firstName; }
    public void setFirstName(String firstName) { this.firstName = firstName; }
    public String getLastName() { return lastName; }
    public void setLastName(String lastName) { this.lastName = lastName; }
    @Override
    public boolean equals(Object obj) {
    if (obj == this) {
        return true;
    }
    if (obj == null || obj.getClass() != this.getClass()) {
        return false;
    }

    Person guest = (Person) obj;
    return id == guest.id
        && (firstName == guest.firstName
            || (firstName != null &&firstName.equals(guest.getFirstName())))        && (lastName == guest.lastName
            || (lastName != null && lastName .equals(guest.getLastName())
            ));
    }
    @Override
    public int hashCode() {
    final int prime = 31;
    int result = 1;
    result = prime * result + ((firstName == null) ? 0 : firstName.hashCode());             result = prime * result + id; result = prime * result +
        ((lastName == null) ? 0 : lastName.hashCode()); return result;
    }
 }

Распространенные ошибки при переопределении equals в Java

  1. Вместо того, чтобы переопределять метод equals (Override) программист перегружает его (Overload)Синтаксис метода equals() в классе Object определен Jak public boolean equals(Object obj), но многие программисты ненароком перегружают метод: public boolean equals(Person obj) - zamiast Object в качестве аргумента используют Nazwa своего класса (напр. Person). Эту ошибку сложно обнаружить из-за static binding. Таким образом, если вы вызовете этот метод для obiektа своего класса, то метод не просто скомпLubруется, а даже сделает это корректно. Однако, если вы положите ваш obiekt в коллекцию, например ArrayList и вызовете метод contains(), работа которого основана на методе equals(), то метод contains не сможет обнаружить ваш obiekt.

  2. При переопределении метода equals() не проверять на null переменные, что в конечном итоге заканчивается NullPointerException при вызове equals(). Ниже представлен корректный kod.

    firstname == guest.firstname || (firstname != null &&
         firstname.equals(guest.firstname));
  3. Третья распространенная ошибка это не переопределять метод hashCode(), а только equals(). Вы обязаны переопределять оба метода equals() и hashCode() в Java. Метод hashCode используется в hash -коллекциях(например HashSet), и чем меньше будет коллизий (одинаковый kod при разных obiektах) тем эффективнее эти коллекции будут работать с obiektами вашего класса.

  4. Последняя распространенная ошибка программистов в том, что при переопределении метода equals() не сохраняется соответствие между методами equals() и compareTo(), что является неформальным требованием для избежания хранения дубликатов в Set (SortedSet, TreeSet).

Подсказки Jak писать в Java метод equals

  1. Большинство IDE такие Jak NetBeans, Eclipse и IntelliJ IDEA обеспечивают поддержку генерации методов equals() и hashCode(). В Eclipse нажмите правую кнопку -> source -> generate equals() и hashCode().

  2. Если в классе есть уникальный бизнес-ключ, то будет достаточно сделать проверку только на równa sięство этих полей. Как в нашем примере “id” - уникальный номер для каждого Person.

  3. При переопределении hashCode() в Java удостоверьтесь в использовании всех полей, что были использованы в методе equals().

  4. String и классы-оболочки такие Jak Integer, Float и Double переопределяют метод equals(), но StringBuffer не переопределяет.

  5. При любой возможности делайте поля immutable используя final переменные в Java.

  6. При сравнении String obiektов используйте equals() zamiast оператора ==.

  7. Dwa obiekty, które są logicznie równe, ale załadowane z różnych obiektów, ClassLoadernie mogą być równe. Pamiętaj, że sprawdzenie za pomocą getClass()zwróci false, jeśli klasa programu ładującego jest inna.

  8. Użyj @Overrideadnotacji również w metodzie . hashCode, ponieważ zapobiega to subtelnym błędom, takim jak wartość zwracana przez int. Jednakże niektórzy programiści zwracają long.

PS Drodzy koledzy! Uważam, że ten artykuł jest przydatny w rozwiązywaniu problemów poziomu 21! Życzę powodzenia w analizowaniu tego tematu, skorzystaj z tłumaczenia! Mam nadzieję, że pomożecie mi podnieść moją ocenę, bo teraz nie mogę nawet zostawić komentarza na tym forum. Wielkie dzięki wszystkim! Artykuł oryginalny Pominąłem niektóre punkty ze względu na brak wolnego czasu, ale przetłumaczyłem wszystko, co musisz wiedzieć, aby rozwiązać problemy poziomu 21.
Komentarze
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION