JavaRush /Java Blog /Random-TW /Java 中重載 equals() 和 hashCode() 方法
Coder
等級 17

Java 中重載 equals() 和 hashCode() 方法

在 Random-TW 群組發布

重寫 Java 中的 equals() 和 hashCode() 方法

EqualshashCode是在類別中聲明Object並包含在標準 Java 庫中的基本方法。 Java 中重載 equals() 和 hashCode() 方法 - 1此方法еquals()用於比較物件並hashCode為物件產生整數程式碼。這些方法在 Java 標準庫中廣泛用於在HashMap. 此方法equal還用於確保在HashSet其他Set實作中以及需要比較物件的任何其他情況下僅儲存唯一物件。equals()類別中該方法的預設實作java.lang.Object會比較變數儲存的記憶體位址的引用,true僅當位址匹配時才返回,換句話說,變數引用同一物件。如果您希望根據自然邏輯或業務邏輯進行比較,Java 建議重寫equals()和方法。hashCode()標準 Java 庫中的許多類別都會重寫它們,例如,類別String會重寫equals,以便true在比較的兩個物件的內容相同時返回。包裝類別重寫Integer方法equal以執行數值比較等。由於JavaHashMap也依賴和方法來比較它們的和,因此 Java 提供了以下規則來重寫這些方法: HashTableequals()hashCode()keyvalues
  1. 自反性:對象必須等於其自身。
  2. 對稱:如果a.equals(b)它返回true,那麼b.equals(a)它也必須返回true
  3. 傳遞性:如果a.equals(b)它返回true並且b.equals(c)也返回true,那麼c.equals(a)它也必須返回true
  4. equals()一致性:只要物件的某些屬性值不會改變,重複呼叫一個方法就必須傳回相同的值。也就是說,如果兩個物件在Java中相等,那麼只要它們的屬性保持不變,它們就相等。
  5. 比較null:必須檢查物件null。如果該物件等於null,則該方法應該返回false,而不是NullPointerException。例如,a.equals(null)它應該返回false.

Java中equals和hashCode的約定

  1. 如果方法執行結果相同equals,那麼它們hashcode一定是相同的。
  2. 如果物件在方法執行的結果中不相等equals,那麼它們hashcode可以相同也可以不同。但是,為了提高效能,最好讓不同的物件傳回不同的程式碼。

Как переопределять метод equals в Java

  1. @Override
    public boolean equals(Object obj) {
    /*1. Check*/if (obj == this) {
    /*and return */ return true;
             }
  2. Проверьте an object на null, а также проверьте, чтобы an objectы были одного типа. Не делайте проверку с помощью instanceof так How такая проверка будет возвращать true для подклассов и будет работать правильно только в случае если ваш класс объявлен How immutable. Вместо этого можно использовать 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 определен How public boolean equals(Object obj), но многие программисты ненароком перегружают метод: public boolean equals(Person obj) - instead of Object в качестве аргумента используют Name своего класса (напр. Person). Эту ошибку сложно обнаружить из-за static binding. Таким образом, если вы вызовете этот метод для an object своего класса, то метод не просто скомпorруется, а даже сделает это корректно. Однако, если вы положите ваш an object в коллекцию, например ArrayList и вызовете метод contains(), работа которого основана на методе equals(), то метод contains не сможет обнаружить ваш an object.

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

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

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

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

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

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

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

  4. String和包裝類別等IntegerFloatDouble重寫方法equals(),但StringBuffer不重寫。

  5. 只要有可能,在 Java 中immutable使用final變數來建立欄位。

  6. 比較String物件時,請使用equals(). 運算子==

  7. 邏輯上相等但從不同物件載入的兩個物件ClassLoader不能相等。請記住,如果載入器類別不同,則檢查getClass()將返回。false

  8. 在 . 方法上也使用@Override註釋hashCode,因為這可以防止微妙的錯誤,例如 . 的返回值int。但是,有些程式設計師會回傳long.

PS 親愛的同事們!我發現這篇文章對於解決 21 級問題很有用!祝你分析這個主題好運,使用翻譯!我希望你能幫助我提高我的評分,因為現在我甚至無法在這個論壇上發表評論。非常感謝大家! 由於缺乏空閒時間, 原文章中我省略了一些要點,但我翻譯了解決 21 級問題所需了解的所有內容。
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION