JavaRush /בלוג Java /Random-HE /עבודה עם שיטות hashCode() ו- equals() ב-Java
Lenchik854
רָמָה
Chernihiv

עבודה עם שיטות hashCode() ו- equals() ב-Java

פורסם בקבוצה
בפוסט זה אתאר את ההבנה שלי בשיטות hashCode()ו equals(). אני רוצה לדבר על יישום ברירת המחדל שלהם, כמו גם איך לעקוף אותם בצורה נכונה. אכתוב גם על הטמעת שיטות אלו באמצעות מחלקות העזר של חבילת Apache Common. עבודה עם שיטות hashCode() ו- equals() ב-Java - 1תוכן הפוסט הזה:
  1. באמצעות hashCode()ו equals().
  2. עוקף את התנהגות ברירת המחדל.
  3. עקיפה hashCode()ושימוש equals()ב- Apache Commons Lang.
  4. משהו שחשוב לזכור.
  5. תשומת לב מיוחדת בעת שימוש ב-ORM.
מתודות hashCode()ו equals()הוגדרו במחלקה Object, שהיא מחלקת האב עבור אובייקטי Java. לכן, כל אובייקטי Java יורשים את מימוש ברירת המחדל משיטות אלה.

שימוש ב-hashCode() ושווה()

השיטה hashCode()משמשת לקבלת מספר שלם ייחודי עבור אובייקט נתון. כאשר יש לאחסן אובייקט כמבנה נתונים בטבלת hash (נקראת גם bucket), מספר זה משמש לקביעת מיקומו בטבלה זו. כברירת מחדל, השיטה hashCode()עבור אובייקט מחזירה את המספר של מיקום הזיכרון שבו האובייקט מאוחסן. השיטה equals(), כפי ששמה מרמז, משמשת פשוט כדי לבדוק את השוויון של שני אובייקטים. יישום ברירת המחדל של שיטה זו פשוט בודק את ההפניות של שני אובייקטים כדי לראות אם הם שווים.

עוקף התנהגות ברירת מחדל

הכל עובד בסדר כל עוד אתה לא מעקף אף אחת מהשיטות האלה בשיעורים שלך. אבל לפעמים יישומים צריכים לשנות את התנהגות ברירת המחדל של אובייקטים מסוימים. ניקח דוגמה שבה יש לך Employee. בוא נכתוב את המבנה המינימלי האפשרי של מחלקה כזו.
public class Employee
{
    private Integer id;
    private String firstname;
    private String lastName;
    private String department;

    public Integer getId() {
        return id;
    }
    public void setId(Integer 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;
    }
    public String getDepartment() {
        return department;
    }
    public void setDepartment(String department) {
        this.department = department;
    }
}
למחלקה המתוארת למעלה Employeeיש כמה תכונות בסיסיות ושיטות עזר. כעת נסתכל על מצב פשוט שבו עלינו להשוות בין שני אובייקטים של המחלקה Employee.
public class EqualsTest {
    public static void main(String[] args) {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);
        //Печатает false в консоли
        System.out.println(e1.equals(e2));
    }
}
לא צריך ראיית רוח כדי לנחש שהשיטה שנכתבה למעלה תחזיר "שקר". אבל האם זה באמת נכון, בהתחשב בכך ששני האובייקטים הללו זהים? ביישום בזמן אמת, השיטה חייבת להחזיר אמת. כדי להשיג את ההתנהגות הנכונה, עלינו לעקוף את השיטה equals(), כפי שנעשה להלן:
public boolean equals(Object o) {
        if(o == null)
        {
            return false;
        }
        if (o == this)
        {
           return true;
        }
        if (getClass() != o.getClass())
        {
            return false;
        }
        Employee e = (Employee) o;
        return (this.getId() == e.getId());
}
הוסף שיטה זו לכיתה שלך Employeeובדיקת השוויון תחזיר "נכון". עם זאת, האם עשינו הכל? עדיין לא. בואו נבדוק את הכיתה המותאמת שלנו בדרך אחת נוספת.
import java.util.HashSet;
import java.util.Set;

public class EqualsTest
{
    public static void main(String[] args)
    {
        Employee e1 = new Employee();
        Employee e2 = new Employee();

        e1.setId(100);
        e2.setId(100);

        //Печатает 'true'
        System.out.println(e1.equals(e2));

        Set employees = new HashSet();
        employees.add(e1);
        employees.add(e2);
        //Печатает два an object
        System.out.println(employees);
    }
}
הפקודה System.out.println(employee)מדפיסה שני אובייקטים. אם שני האובייקטים היו שווים, ורק Setאובייקטים ייחודיים היו כלולים, אז HashSetצריך להיות רק מופע אחד בפנים, כלומר. שני האובייקטים מתייחסים לאותם מופעים של המחלקה Employee. מה פספסנו? פספסנו את השיטה החשובה השנייה hashCode(). כפי שאומר התיעוד של Java, אם אתה עוקף את השיטה equals(), אתה נדרש לעקוף את השיטה hashCode(). אז בואו נוסיף שיטה נוספת לכיתה שלנו Employee.
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    int result = 1;
    result = PRIME * result + getId();
    return result;
 }
הוספנו שיטה זו פעם אחת למחלקה שלנו, ורק אובייקט אחד יודפס, וכך, בדיקת השקילות של e1 ו-e2 הראתה אמת.

עקיפה hashCode()ושימוש equals()ב- Apache Commons Lang

Apache Commons מספק שני שיעורי עוזר נהדרים לשיטות קריאה hashCode()ו- equals(). להלן אנו רואים את השימוש:
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.builder.HashCodeBuilder;
public class Employee
{
 private Integer id;
 private String firstname;
 private String lastName;
 private String department;
public Integer getId() {
    return id;
 }
 public void setId(Integer 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;
 }
 public String getDepartment() {
    return department;
 }
 public void setDepartment(String department) {
    this.department = department;
 }
@Override
 public int hashCode()
 {
    final int PRIME = 31;
    return new HashCodeBuilder(getId()%2==0?getId()+1:getId(), PRIME).
           toHashCode();
 }
@Override
 public boolean equals(Object o) {
    if (o == null)
       return false;
    if (o == this)
       return true;
    if (o.getClass() != getClass())
       return false;
    Employee e = (Employee) o;
       return new EqualsBuilder().
              append(getId(), e.getId()).
              isEquals();
    }
 }
מצד שני, אם אתה משתמש באחד מעורכי הקוד, הם אמורים גם להיות מסוגלים לקרוא כמה מבנים נחמדים עבורך. לדוגמה, אם ב-Eclipse IDE תלחץ לחיצה ימנית על class >> source > Generating hashCode() ו-equals() ... זה יפיק עבורך יישום נחמד מאוד. עבודה עם שיטות hashCode() ו- equals() ב-Java - 2משהו שחשוב לזכור.
  1. השתמש תמיד באותן תכונות אובייקט כדי לקרוא גם וגם hashCode()וגם equals(). רק במקרה שלנו, השתמשנו ב employee id.
  2. השיטה equals()חייבת להיות מתמשכת (אם האובייקט לא השתנה, השיטה חייבת להחזיר את אותו הערך).
  3. בכל פעם a.equals(b), אז a.hashCode()חייב להיות זהה ל b.hashCode().
  4. אם תעקוף שיטה אחת, עליך לעקוף את השנייה.

תשומת לב מיוחדת בעת שימוש ב-ORM

אם אתה מתמודד עם ORM (ru.wikipedia.org/wiki/ORM), השתמש תמיד ב-Gutters ולעולם אל תשתמש בהפניות לשדה hashCode(). equals()הסיבה לכך היא שב-ORM, מעת לעת שדות נטענים באמצעות עומס עצלן ואינם נגישים עד לקריאת הגטרים שלהם. לדוגמה, בכיתה שלנו Employee, אנו משתמשים ב e1.id == e2.id. זה בהחלט אפשרי ששדות id נטענים באמצעות טעינה עצלה. אחד מהשדות עשוי להיות 0 או null ונקבל התנהגות שגויה. אבל, אם נעשה שימוש ב- e1.getId() == e2.getId(), אנחנו יכולים להיות בטוחים גם אם השדות נטענו באמצעות טעינה עצלה; קריאה ל-getter תאכלס את השדה תחילה. זה כל מה שאני יודע על השיטות hashCode()והשיטות equals(). מקווה שזה יעזור למישהו איפשהו. בהצלחה עם הלימודים שלך!! נ.ב. זה הניסיון הראשון שלי לתרגום. ניסיתי להעביר הכל כמה שיותר קרוב למה שהסופר רצה לומר. אם יש לכם הערות, אנא כתבו בתגובות. אל תשפוט בקפדנות :-))) מאמר מקורי
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION