قرارداد بین ()quals و hashcode() چیست؟ یاد بگیرید که چگونه این روش ها هنگام مقایسه اشیاء جاوا با هم کار می کنند.
equals()
و hashcode()
جاوا دو روشی هستند که با هم کار می کنند تا بررسی کنند که آیا دو شی دارای مقدار یکسانی هستند یا خیر. میتوانید از آنها برای مقایسه آسان و کارآمد در برنامههای جاوا استفاده کنید.
استفاده از برابر () و hashcode() در جاوا
در این مقاله، یاد خواهید گرفت:
- چرا
equals()
وhashcode()
را در جاوا لغو کنید؟ - نحوه مقایسه اشیاء جاوا با
equals()
- نحوه شناسایی اشیاء جاوا با
hashcode()
- نحوه استفاده از
equals()
وhashcode()
با مجموعه ها
همچنین دریافت خواهید کرد:
- دستورالعملهایی برای استفاده از
equals()
وhashcode()
- قوانین مقایسه اشیا با
equals()
وhashcode()
- اشتباهاتی که هنگام استفاده از
equals()
وhashcode()
- چه چیزی را در مورد
equals()
وhashcode()
اجتناب کنید
به خاطر بسپارید
خط پایین: چرا از برابر () و hashcode() استفاده کنیم؟
بدون equals()
و hashcode()
، باید هر فیلد را از یک شی مقایسه کنیم. کد بسیار گیج کننده و خواندن آن سخت خواهد بود. استفاده از روشهای equals()
و hashcode()
با هم منجر به کد انعطافپذیرتر و منسجمتر میشود.
چرا override برابر با() و hashcode() در جاوا است؟
بازگردانی روش تکنیکی است که در آن رفتار کلاس یا رابط والد دوباره در زیر کلاس نوشته میشود (بازنویسی میشود) تا از مزیت Polymorphism استفاده شود. هر Object
در جاوا شامل یک روش equals()
و یک hashcode()
است، اما برای درست کار کردن باید آنها را لغو کرد.
برای درک اینکه چگونه overriding با equals()
و hashcode()
کار میکند، میتوانیم اجرای آنها را در کلاسهای اصلی جاوا مطالعه کنیم. در زیر متد equals()
در کلاس Object
آمده است. این روش بررسی میکند که آیا نمونه فعلی مشابه Object
قبلی است یا خیر.
public boolean equals(Object obj) {
return (this == obj);
}
وقتی روش hashcode()
لغو نشود، روش پیشفرض در کلاس Object
فراخوانی میشود. این یک روش بومی است، به این معنی که در زبان دیگری مانند C اجرا میشود و مقداری کد مربوط به آدرس حافظه شی را برمیگرداند. (این مهم نیست که دقیقاً بدانید این روش چگونه کار می کند مگر اینکه در حال نوشتن کد JDK باشید.)
@HotSpotIntrinsicCandidate
public native int hashCode();
وقتی روشهای equals()
و hashcode()
لغو نمیشوند، به جای آن متدهای بالا را فراخوانی میکنید. در این مورد، متدها هدف واقعی equals()
و hashcode()
را برآورده نمیکنند، یعنی بررسی اینکه آیا دو یا چند شی دارای مقادیر یکسان هستند.< /p>
به عنوان یک قاعده، وقتی equals()
را لغو میکنید، باید hashcode()
را نیز لغو کنید.
کد را دریافت کنید
کد منبع چالشهای جاوا را دریافت کنید.
نحوه مقایسه اشیاء با ()quals
ما از متد equals()
برای مقایسه اشیاء در جاوا استفاده می کنیم. برای تعیین یکسان بودن دو شیء، equals()
مقادیر ویژگی های اشیاء را با هم مقایسه می کند:
public class EqualsAndHashCodeExample {
public static void main(String... equalsExplanation) {
System.out.println(new Simpson("Homer", 35, 120)
.equals(new Simpson("Homer",35,120)));
System.out.println(new Simpson("Bart", 10, 120)
.equals(new Simpson("El Barto", 10, 45)));
System.out.println(new Simpson("Lisa", 54, 60)
.equals(new Object()));
}
static class Simpson {
private String name;
private int age;
private int weight;
public Simpson(String name, int age, int weight) {
this.name = name;
this.age = age;
this.weight = weight;
}
@Override
public boolean equals(Object o) {
if (this == o) {
return true;
}
if (o == null || getClass() != o.getClass()) {
return false;
}
Simpson simpson = (Simpson) o;
return age == simpson.age &&
weight == simpson.weight &&
name.equals(simpson.name);
}
}
}
در مقایسه اول، equals()
نمونه شی فعلی را با شی ای که ارسال شده مقایسه می کند. اگر دو شی مقادیر یکسانی داشته باشند، equals()
true
را برمیگرداند.
در مقایسه دوم، equals()
بررسی می کند که آیا شیء ارسال شده null است یا به عنوان کلاس دیگری تایپ شده است. اگر کلاس متفاوتی باشد، اشیاء برابر نیستند.
در نهایت، equals()
فیلدهای اشیا را با هم مقایسه می کند. اگر دو شیء دارای مقادیر فیلد یکسانی باشند، آنگاه شیءها یکسان هستند.
مقایسه اشیا
اکنون، اجازه دهید نتایج این مقایسهها را در روش main()
خود مشاهده کنیم. ابتدا دو شی Simpson
را با هم مقایسه می کنیم:
System.out.println(new Simpson("Homer", 35, 120).equals(new Simpson("Homer", 35, 120)));
اشیاء در اینجا یکسان هستند، بنابراین نتیجه true
خواهد بود.
بعد، دوباره دو شی Simpson
را با هم مقایسه می کنیم:
System.out.println(new Simpson
("Bart", 10, 45).equals(new Simpson
("El Barto", 10, 45)));
اشیاء اینجا تقریباً یکسان هستند اما نام آنها متفاوت است: بارت و ال بارتو. بنابراین نتیجه نادرست
خواهد بود.
در نهایت، بیایید یک شی Simpson
و یک نمونه از کلاس شیء:
System.out.println(new Simpson
("Lisa", 54, 60).equals(new Object
()));
در این مورد، نتیجه نادرست
خواهد بود زیرا انواع کلاسها متفاوت است.
equals() با ==
یکسان نیست
در نگاه اول، عملگر ==
و متد equals()
ممکن است کار مشابهی را انجام دهند، اما متفاوت عمل میکنند. عملگر ==
مقایسه می کند که آیا دو مرجع شی به یک شی اشاره دارند یا خیر. به عنوان مثال:
System.out.println(homer == homer2);
در اولین مقایسه، ما دو نمونه مختلف Simpson
را با استفاده از عملگر new
نمونهسازی کردیم. به همین دلیل، متغیرهای homer
و homer2
به مراجع مختلف Object
در هپ حافظه. بنابراین ما false
را به عنوان نتیجه خواهیم داشت.
System.out.println(homer.equals(homer2));
در مقایسه دوم، روش equals()
را لغو میکنیم. در این مورد فقط نام ها مقایسه می شوند. از آنجایی که نام هر دو شی Simpson
“Homer” است، نتیجه true
است.
نحوه شناسایی اشیاء با hashcode()
ما از روش hashcode()
برای بهینه سازی عملکرد هنگام مقایسه اشیا استفاده می کنیم. اجرای hashcode()
یک شناسه منحصر به فرد برای هر شیء در برنامه شما برمی گرداند، که کار مقایسه کل وضعیت شی را بسیار آسان می کند.
اگر هش کد یک شی با هش کد شی دیگر یکسان نیست، دلیلی برای اجرای متد equals()
وجود ندارد: فقط می دانید که این دو شی یکسان نیستند. از طرف دیگر، اگر کد هش یکسان است، باید متد equals()
را اجرا کنید تا تعیین کنید که آیا مقادیر و فیلدها یکسان هستند یا نه.
در اینجا یک مثال عملی با hashcode()
آورده شده است.
public class HashcodeConcept {
public static void main(String... hashcodeExample) {
Simpson homer = new Simpson(1, "Homer");
Simpson bart = new Simpson(2, "Homer");
boolean isHashcodeEquals = homer.hashCode() == bart.hashCode();
if (isHashcodeEquals) {
System.out.println("Should compare with equals method too.");
} else {
System.out.println("Should not compare with equals method because " +
"the id is different, that means the objects are not equals for sure.");
}
}
static class Simpson {
int id;
String name;
public Simpson(int id, String name) {
this.id = id;
this.name = name;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Simpson simpson = (Simpson) o;
return id == simpson.id &&
name.equals(simpson.name);
}
@Override
public int hashCode() {
return id;
}
}
}
یک hashcode()
که همیشه همان مقدار را برمیگرداند معتبر است اما چندان مؤثر نیست. در این حالت مقایسه همیشه true
را برمیگرداند، بنابراین روش equals()
همیشه اجرا میشود. در این مورد هیچ بهبودی در عملکرد وجود ندارد.
نحوه استفاده از برابر () و hashcode() با مجموعه ها
رابط Set
مسئول اطمینان از اینکه هیچ عنصر تکراری در زیر کلاس Set
درج نمیشود، است. در زیر برخی از کلاس هایی هستند که رابط Set
را پیاده سازی می کنند:
فقط عناصر منحصربهفرد را میتوان در Set
درج کرد، بنابراین اگر میخواهید عنصری را به کلاس HashSet
اضافه کنید (به عنوان مثال)، ابتدا باید از < استفاده کنید code>equals() و روشهای hashcode()
برای تأیید اینکه عنصر منحصر به فرد است. اگر روشهای equals()
و hashcode()
در این مورد نادیده گرفته نمیشوند، خطر درج عناصر تکراری در کد وجود دارد.
در کد زیر، از روش add
برای افزودن یک عنصر جدید به یک شی HashSet
استفاده میکنیم. قبل از اینکه عنصر جدید اضافه شود، HashSet
بررسی میکند که آیا عنصر از قبل در مجموعه داده شده وجود دارد یا خیر:
if (e.hash == hash && ((k = e.key) == key || (key != null && key.equals(k))))
break;
p = e;
اگر شیء یکسان باشد، عنصر جدید درج نخواهد شد.
مجموعه های هش
Set
تنها مجموعهای نیست که از equals()
و hashcode()
استفاده میکند. HashMap، Hashtable، و LinkedHashMap نیز به این روش ها نیاز دارد. به عنوان یک قاعده، اگر مجموعهای را میبینید که پیشوند «Hash» دارد، میتوانید مطمئن باشید که نیاز به لغو روشهای hashcode()
و equals()
دارد. ویژگی های آنها به درستی کار کند.
دستورالعملهایی برای استفاده از برابر () و hashcode()
شما فقط باید یک متد equals()
را برای اشیایی که دارای شناسه هش کد منحصر به فرد یکسانی هستند اجرا کنید. وقتی شناسه کد هش متفاوت است، equals()
را نباید اجرا کنید.
جدول ۱. مقایسه کدهای هش
اگر مقایسه hashcode() … |
سپس… |
---|---|
درست برمیگرداند | equals() |
نادرست را برمی گرداند | equals() |
این اصل عمدتاً در مجموعههای Set
یا Hash
به دلایل عملکرد استفاده میشود.
قوانین مقایسه شی با ()quals و hashcode()
وقتی مقایسه hashcode()
false
را برمیگرداند، روش equals()
باید false را نیز برگرداند. اگر کد هش متفاوت باشد، قطعاً اشیاء برابر نیستند.
جدول ۲. مقایسه شیء با hashcode()
وقتی مقایسه کد هش برمی گردد … | متد equals() باید به … |
---|---|
درست | درست یا نادرست |
نادرست | نادرست |
وقتی روش equals()
true
را برمیگرداند، به این معنی است که اشیاء در همه مقادیر و ویژگیها برابر هستند. در این مورد، مقایسه کد هش نیز باید درست باشد.
جدول ۳. مقایسه شیء با برابر ()
وقتی متد equals() … |
روش hashcode() باید … |
---|---|
درست | درست |
نادرست | درست یا نادرست |
چالش برابر () و hashcode() را انتخاب کنید!
وقت آن است که مهارتهای خود را با equals()
و hashcode()
آزمایش کنید. هدف شما در این چالش این است که خروجی دو مقایسه روش equals()
را مشخص کنید و اندازه مجموعه Set
را حدس بزنید.
برای شروع، کد زیر را با دقت مطالعه کنید:
public class EqualsHashCodeChallenge {
public static void main(String... doYourBest) {
System.out.println(new Simpson("Bart").equals(new Simpson("Bart")));
Simpson overriddenHomer = new Simpson("Homer") {
public int hashCode() {
return (43 + 777) + 1;
}
};
System.out.println(new Simpson("Homer").equals(overriddenHomer));
Set set = new HashSet(Set.of(new Simpson("Homer"), new Simpson("Marge")));
set.add(new Simpson("Homer"));
set.add(overriddenHomer);
System.out.println(set.size());
}
static class Simpson {
String name;
Simpson(String name) {
this.name = name;
}
@Override
public boolean equals(Object obj) {
Simpson otherSimpson = (Simpson) obj;
return this.name.equals(otherSimpson.name) &&
this.hashCode() == otherSimpson.hashCode();
}
@Override
public int hashCode() {
return (43 + 777);
}
}
}
به خاطر داشته باشید، ابتدا کد را تجزیه و تحلیل کنید، نتیجه را حدس بزنید، سپس کد را اجرا کنید. هدف شما بهبود مهارت خود با تجزیه و تحلیل کد و جذب مفاهیم اصلی جاوا برای قدرتمندتر کردن کد شما است. قبل از بررسی پاسخ صحیح زیر، پاسخ خود را انتخاب کنید.
A)
true
true
۴
B)
true
false
۳
C)
true
false
۲
D)
false
true
۳
چه اتفاقی افتاد؟
در اولین مقایسه روش equals()
، نتیجه true
است زیرا وضعیت شی دقیقاً یکسان است و hashcode() متد code> مقدار یکسانی را برای هر دو شی برمیگرداند.
در مقایسه روش دوم equals()
، روش hashcode()
برای متغیر overridenHomer
نادیده گرفته می شود. نام "Homer" برای هر دو شی Simpson
است، اما روش hashcode()
مقدار متفاوتی را برای overriddenHomer
برمیگرداند. در این حالت، نتیجه نهایی از روش equals()
false
خواهد بود زیرا این روش شامل مقایسه با کد هش است.
ممکن است متوجه شوید که اندازه مجموعه برای نگهداری سه شی Simpson
تنظیم شده است. بیایید این را با جزئیات بررسی کنیم.
اولین شیء در مجموعه خواهد بود به طور معمول درج می شود:
new Simpson("Homer");
شیء بعدی نیز به طور معمول درج خواهد شد، زیرا مقداری متفاوت از شیء قبلی دارد:
new Simpson("Marge");
در نهایت، شئ Simpson
زیر همان مقدار شیء اول را دارد. در این حالت شی درج نخواهد شد:
set.add(new Simpson("Homer"));
همانطور که می دانیم، شی overridenHomer
از مقدار کد هش متفاوت از نمونه معمولی Simpson("Homer")
استفاده می کند. به همین دلیل، این عنصر در مجموعه درج می شود:
overriddenHomer;
کلید پاسخ
پاسخ این چالش کننده جاوا B است. خروجی این خواهد بود:
true
false
۳
پست های مرتبط
مقایسه اشیاء جاوا با ()quals و hashcode()
مقایسه اشیاء جاوا با ()quals و hashcode()
مقایسه اشیاء جاوا با ()quals و hashcode()