JavaRush /وبلاگ جاوا /Random-FA /کار با متدهای hashCode() و equals() در جاوا
Lenchik854
مرحله
Chernihiv

کار با متدهای hashCode() و equals() در جاوا

در گروه منتشر شد
در این پست درک خود را از روش ها hashCode()و equals(). من می خواهم در مورد اجرای پیش فرض آنها و همچنین نحوه نادیده گرفتن صحیح آنها صحبت کنم. من همچنین در مورد پیاده سازی این روش ها با استفاده از کلاس های کمکی بسته Apache Common خواهم نوشت. کار با متدهای hashCode() و equals() در جاوا - 1مطالب این پست:
  1. با استفاده hashCode()از و equals().
  2. نادیده گرفتن رفتار پیش فرض
  3. نادیده گرفتن hashCode()و equals()استفاده از Apache Commons Lang.
  4. چیزی که یادآوری آن مهم است.
  5. توجه ویژه هنگام استفاده از ORM.
متدهای hashCode()and equals()در کلاس تعریف شده است Objectکه کلاس والد برای اشیاء جاوا است. بنابراین، تمام اشیاء جاوا پیاده سازی پیش فرض را از این متدها به ارث می برند.

استفاده از hashCode() و برابر ()

این روش hashCode()برای به دست آوردن یک عدد صحیح منحصر به فرد برای یک شی داده شده استفاده می شود. هنگامی که یک شی باید به عنوان یک ساختار داده در یک جدول هش (که سطل نیز نامیده می شود) ذخیره شود، از این عدد برای تعیین مکان آن در آن جدول استفاده می شود. به‌طور پیش‌فرض، متد 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));
    }
}
حدس زدن اینکه روش نوشته شده در بالا "نادرست" را برمی گرداند، نیازی به یک روشن بین نیست. اما آیا با توجه به یکسان بودن این دو شی در واقع این درست است؟ در برنامه بلادرنگ، متد باید true را برگرداند. برای دستیابی به رفتار صحیح، باید روش را نادیده بگیریم 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و بررسی معادل "true" برمی گردد. با این حال، آیا ما همه کارها را انجام داده ایم؟ نه هنوز. بیایید کلاس اصلاح شده خود را به روشی دیگر آزمایش کنیم.
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(). همانطور که مستندات جاوا می گوید، اگر روش را لغو کنید 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() راست کلیک کنید و برابر ()... پیاده سازی بسیار خوبی برای شما ایجاد می کند. کار با متدهای hashCode() و equals() در جاوا - 2چیزی که یادآوری آن مهم است.
  1. همیشه از همان ویژگی های شیء برای فراخوانی هر دو و hashCode()و استفاده کنید equals(). فقط در مورد ما، ما استفاده کردیم employee id.
  2. متد equals()باید پایدار باشد (اگر شی تغییر نکرده باشد، متد باید همان مقدار را برگرداند).
  3. هر وقت a.equals(b), آنگاه a.hashCode()باید همان باشد b.hashCode().
  4. اگر یک روش را لغو کنید، باید روش دوم را لغو کنید.

توجه ویژه هنگام استفاده از ORM

اگر با ORM سر و کار دارید (ru.wikipedia.org/wiki/ORM)، همیشه از دریافت کننده ها استفاده کنید و هرگز از مراجع فیلد استفاده نکنید hashCode(). equals()این به این دلیل است که در یک ORM، هر از گاهی فیلدها با استفاده از بار تنبل بارگذاری می شوند و تا زمانی که گیرنده های آنها فراخوانی نشود، قابل دسترسی نیستند. به عنوان مثال، در کلاس خود Employeeاز e1.id == e2.id. کاملاً ممکن است که iفیلدهای d با استفاده از بارگذاری تنبل بارگیری شوند. ممکن است یکی از فیلدها صفر یا تهی باشد و رفتار نادرستی دریافت کنیم. اما، اگر استفاده شود e1.getId() == e2.getId()، می‌توانیم مطمئن باشیم حتی اگر فیلدها با استفاده از بارگذاری تنبل بارگذاری شده باشند. فراخوانی گیرنده ابتدا فیلد را پر می کند. این تمام چیزی است که من در مورد hashCode()و روش ها می دانم equals(). امیدوارم این به کسی در جایی کمک کند. با آرزوی موفقیت در تحصیل!! این اولین تلاش من برای ترجمه است. سعی کردم همه چیز را تا جایی که ممکن است به آنچه نویسنده می‌خواسته بگوید نزدیک کنم. اگر نظری دارید در نظرات بنویسید. به شدت قضاوت نکنید :-))) مقاله اصلی
نظرات
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION