JavaRush /בלוג Java /Random-HE /עומס יתר של שיטות equals() ו-hashCode() ב-Java
Coder
רָמָה

עומס יתר של שיטות equals() ו-hashCode() ב-Java

פורסם בקבוצה

עקיפה של שיטות equals() ו-hashCode() ב-Java

Equalsוהן hashCodeהשיטות הבסיסיות המוצהרות במחלקה Objectונכללות בספריות Java הסטנדרטיות. עומס יתר של שיטות equals() ו-hashCode() ב-Java - 1השיטה еquals()משמשת להשוואת אובייקטים וליצירת hashCodeקוד שלם עבור האובייקט. שיטות אלה נמצאות בשימוש נרחב בספריות הסטנדרטיות של Java בעת הכנסה ואחזור של אובייקטים ב HashMap. השיטה equalמשמשת גם כדי להבטיח שרק אובייקטים ייחודיים מאוחסנים ביישומים HashSetאחרים Set, כמו גם בכל מקרים אחרים שבהם יש צורך להשוות אובייקטים. יישום ברירת המחדל של השיטה equals()במחלקה java.lang.Objectמשווה הפניות לכתובות הזיכרון שהמשתנים מאחסנים ומחזיר trueרק אם הכתובות תואמות, במילים אחרות, המשתנים מתייחסים לאותו אובייקט. Java ממליצה לעקוף את שיטות equals()ו hashCode()אם אתה מצפה שההשוואה תיעשה לפי ההיגיון הטבעי או ההיגיון העסקי. מחלקות רבות בספריות Java הסטנדרטיות עוקפות אותן, למשל המחלקה Stringעוקפת equalsכך שהיא חוזרת trueאם התוכן של שני האובייקטים שמשווים זהים. מחלקת ה-wrapper עוקפת Integerאת השיטה equalלביצוע השוואה מספרית, וכן הלאה. מכיוון ש- Java מסתמכת HashMapגם על ושיטות להשוואה שלהם ו- , 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.

הסכם בין equals ו-hashCode ב-Java

  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ומחלקות עטיפה כגון Integer, Floatודרוס Doubleאת השיטה equals(), אך StringBufferאינו עוקף.

  5. במידת האפשר, צור שדות immutableבאמצעות finalמשתנים ב-Java.

  6. בעת השוואת Stringאובייקטים, השתמש equals()במקום זאת באופרטור ==.

  7. שני אובייקטים שווים מבחינה לוגית אך נטענים מאובייקטים שונים ClassLoaderאינם יכולים להיות שווים. זכור שבדיקה עם getClass()תחזור falseאם מחלקת הטעינה שונה.

  8. השתמש @Overrideבהערה גם בשיטת . hashCode, שכן הדבר מונע שגיאות עדינות כמו ערך ההחזרה של ה- int. עם זאת, חלק מהמתכנתים מחזירים long.

נ.ב עמיתים יקרים! מצאתי מאמר זה שימושי בפתרון בעיות ברמה 21! אני מאחל לך בהצלחה בניתוח הנושא הזה, השתמש בתרגום! אני מקווה שתעזרו לי להעלות את הדירוג שלי, כי עכשיו אני אפילו לא יכול להשאיר תגובה בפורום הזה. תודה רבה לכולם! מאמר מקורי השמטתי כמה נקודות בגלל חוסר זמן פנוי, אבל תרגמתי את כל מה שצריך לדעת כדי לפתור בעיות ברמה 21.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION