در این پست درک خود را از روش ها لغو
Apache Commons دو کلاس کمکی عالی برای فراخوانی متدها
hashCode()
و equals()
. من می خواهم در مورد اجرای پیش فرض آنها و همچنین نحوه نادیده گرفتن صحیح آنها صحبت کنم. من همچنین در مورد پیاده سازی این روش ها با استفاده از کلاس های کمکی بسته Apache Common خواهم نوشت. مطالب این پست:
- با استفاده
hashCode()
از وequals()
. - نادیده گرفتن رفتار پیش فرض
- نادیده گرفتن
hashCode()
وequals()
استفاده از Apache Commons Lang. - چیزی که یادآوری آن مهم است.
- توجه ویژه هنگام استفاده از 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()
. فقط در مورد ما، ما استفاده کردیمemployee id
. - متد
equals()
باید پایدار باشد (اگر شی تغییر نکرده باشد، متد باید همان مقدار را برگرداند). - هر وقت
a.equals(b)
, آنگاهa.hashCode()
باید همان باشدb.hashCode()
. - اگر یک روش را لغو کنید، باید روش دوم را لغو کنید.
توجه ویژه هنگام استفاده از ORM
اگر با ORM سر و کار دارید (ru.wikipedia.org/wiki/ORM)، همیشه از دریافت کننده ها استفاده کنید و هرگز از مراجع فیلد استفاده نکنیدhashCode()
. equals()
این به این دلیل است که در یک ORM، هر از گاهی فیلدها با استفاده از بار تنبل بارگذاری می شوند و تا زمانی که گیرنده های آنها فراخوانی نشود، قابل دسترسی نیستند. به عنوان مثال، در کلاس خود Employee
از e1.id == e2.id
. کاملاً ممکن است که i
فیلدهای d با استفاده از بارگذاری تنبل بارگیری شوند. ممکن است یکی از فیلدها صفر یا تهی باشد و رفتار نادرستی دریافت کنیم. اما، اگر استفاده شود e1.getId() == e2.getId()
، میتوانیم مطمئن باشیم حتی اگر فیلدها با استفاده از بارگذاری تنبل بارگذاری شده باشند. فراخوانی گیرنده ابتدا فیلد را پر می کند. این تمام چیزی است که من در مورد hashCode()
و روش ها می دانم equals()
. امیدوارم این به کسی در جایی کمک کند. با آرزوی موفقیت در تحصیل!! این اولین تلاش من برای ترجمه است. سعی کردم همه چیز را تا جایی که ممکن است به آنچه نویسنده میخواسته بگوید نزدیک کنم. اگر نظری دارید در نظرات بنویسید. به شدت قضاوت نکنید :-))) مقاله اصلی
GO TO FULL VERSION