השוואת אובייקטים של Java עם שווה ל- () ו- hashcode ()

בכך צ'לנג'ר Java תלמד כיצד equals()ועל hashcode()לשלב לבצע השוואות אובייקט יעילות וקלות בתוכניות Java שלך. במילים פשוטות, שיטות אלה עובדות יחד כדי לאמת אם לשני אובייקטים יש אותם ערכים.  

בלי equals()ו hashcode()היינו צריכה ליצור גדולות מאוד " if" השוואות, השוואה בכל תחום מאובייקט. זה יהפוך את הקוד למבלבל וקשה לקריאה. יחד, שתי שיטות אלה עוזרות לנו ליצור קוד גמיש ומגובש יותר.

קבל את קוד המקור של Java Challengers.

עקיפת שווה ל- () ו- hashcode () ב- Java

עקיפת שיטה היא טכניקה שבה התנהגות מחלקת ההורים או הממשק נכתבת שוב (נעקפת) בכיתת המשנה על מנת לנצל את הפולימורפיזם. כל Objectבג'אווה כוללת equals()לבין hashcode()שיטה, אבל הם חייבים להיות מבוטלים כדי לעבוד כמו שצריכים.

כדי להבין כיצד פועל דריסה עם equals()ו   hashcode(), אנו יכולים ללמוד יישומם בכיתות Java הליבה. להלן equals()השיטה Objectבכיתה. השיטה בודקת אם המופע הנוכחי זהה לזה שעבר בעבר Object.

 public boolean equals(Object obj) { return (this == obj); } 

כאשר hashcode()השיטה אינה מבוטלת, Objectתופעל שיטת ברירת המחדל בכיתה. זוהי שיטה מקורית , כלומר, היא תבוצע בשפה אחרת כמו C, ותחזיר קוד כלשהו לגבי כתובת הזיכרון של האובייקט. (לא כל כך חשוב לדעת איך עובדת שיטה זו אלא אם כן אתה כותב קוד JDK).

 @HotSpotIntrinsicCandidate public native int hashCode(); 

כאשר equals()ו hashcode()השיטות אינן לדרוס, תראה את השיטות הנ"ל מופעלות במקום. במקרה זה, השיטות אינן ממלאות את המטרה האמיתית של equals()והיא hashcode()לבדוק האם לשני אובייקטים או יותר יש אותם ערכים.

ככלל, כשאתה עוקף equals()עליך גם לעקוף hashcode().

השוואת אובייקטים עם שווה ()

אנו משתמשים equals()בשיטה להשוואת אובייקטים ב- Java. על מנת לקבוע אם שני אובייקטים זהים, 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()בודקים אם האובייקט שהועבר אפס , או שהוא הוקלד כמחלקה אחרת. אם זה סוג אחר אז האובייקטים אינם שווים.

לבסוף, 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))); 

האובייקטים כאן זהים כמעט אך שמותיהם שונים: בארט ואל ברטו. לכן התוצאה תהיה false.

לסיום, בואו נשווה Simpsonאובייקט ומופע של המחלקה Object:

 System.out.println(new Simpson("Lisa", 54, 60).equals(new Object())); 

במקרה זה התוצאה תהיה falseמכיוון שסוגי הכיתות שונים.

שווה () לעומת ==

במבט ראשון, נראה ==שהמפעיל equals()והשיטה עושים את אותו הדבר, אך למען האמת הם עובדים אחרת. ==המפעילה משווה בין שני אזכור האובייקט מצביע על אותו האובייקט. לדוגמה:

 System.out.println(homer == homer2); 

בהשוואה הראשונה, יצרנו שני מופעים שונים Simpsonבאמצעות newהמפעיל. מסיבה זו, המשתנית homerואת homer2יצביעו שונה Objectאזכור בערימת הזיכרון. אז תהיה לנו falseכתוצאה מכך.

System.out.println(homer.equals(homer2)); 

בהשוואה השנייה, אנו עוקפים את equals()השיטה. במקרה זה רק השמות ישוו. מכיוון ששמם של שני Simpsonהאובייקטים הוא "הומר" התוצאה תהיה true.

זיהוי אובייקטים ייחודי עם hashcode ()

אנו משתמשים hashcode()בשיטה כדי לייעל ביצועים בעת השוואת אובייקטים. ביצוע   hashcode()מחזיר מזהה ייחודי לכל אובייקט בתוכנית שלך, מה שמקל על משימת השוואת כל מצב האובייקט.

אם ה- hashcode של אובייקט אינו זהה ל- hashcode של אובייקט אחר, אין שום סיבה לבצע את equals()השיטה: אתה פשוט יודע ששני האובייקטים אינם זהים. מצד השני, אם hashcode הוא זהה, אז אתה חייב לבצע את 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  @Override public int hashCode() { return id; } } } 

A hashcode()שתמיד מחזיר את אותו הערך תקף אך לא יעיל במיוחד. במקרה זה ההשוואה תמיד תחזור true, כך equals()שהשיטה תמיד תבוצע. במקרה זה אין שיפור ביצועים.  

שימוש בשווה () ו- hashcode () עם אוספים

Setהממשק אחראי להבטיח שום אלמנטים כפול יוכנס בתוך Setתת. להלן חלק מהשיעורים המיישמים את Setהממשק:

  • HashSet
  • TreeSet
  • LinkedHashSet
  • CopyOnWriteArraySet

ניתן להכניס רק אלמנטים ייחודיים ל- a Set, לכן אם ברצונך להוסיף אלמנט HashSetלמחלקה (למשל), תחילה עליך להשתמש בשיטות 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()שיטה רק עבור אובייקטים בעלי אותו מזהה hashcode ייחודי. אתה לא צריך לבצע equals()כאשר מזהה hashcode שונה.

טבלה 1. השוואות Hashcode

אם hashcode()ההשוואה ... לאחר מכן …
מחזיר נכון לבצע equals()
מחזיר שקר לא לבצע equals()

עיקרון זה משמש בעיקר באוספים Setאו Hashמסיבות ביצועים.

כללים להשוואת אובייקטים

כאשר hashcode()השוואה חוזרת false, equals()השיטה חייבת להחזיר גם שקר . אם ה- hashcode שונה, אז האובייקטים בהחלט לא שווים.

טבלה 2. השוואת אובייקטים עם hashcode ()

כאשר השוואת ההאש קוד חוזרת ... equals()השיטה צריכה לחזור ...
נָכוֹן אמת או שקר
שֶׁקֶר שֶׁקֶר

כאשר equals()השיטה חוזרת true, המשמעות היא שהאובייקטים שווים בכל הערכים והתכונות . במקרה זה, השוואת hashcode חייבת להיות נכונה גם כן.

טבלה 3. השוואת אובייקטים עם שווה ()

כאשר equals()תשואות השיטה ... hashcode()השיטה צריכה לחזור ...
נָכוֹן נָכוֹן
שֶׁקֶר אמת או שקר

קח את האתגר שווה () ו- hashcode ()!

It’s time to test your skills with the equals() and hashcode() methods.  Your goal in this challenge is to figure out the output of the two equals() method comparisons and guess the size of the Set collection.

To start, study the following code carefully:

 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); } } } 

Remember, analyze the code first, guess the result, and then run the code. Your goal is to improve your skill with code analysis and absorb core Java concepts to make your code more powerful. Choose your answer before checking the correct answer below.

 A) true true 4 B) true false 3 C) true false 2 D) false true 3 

What just happened? Understanding equals() and hashcode()

In the first equals() method comparison, the result is true because the state of the object is exactly the same and the hashcode() method returns the same value for both objects.

In the second equals() method comparison, the hashcode() method is being overridden for the overridenHomer variable. The name is “Homer” for both Simpson objects, but the hashcode() method returns a different value for overriddenHomer. In this case, the final result from the the equals() method will be false because the method contains a comparison with the hashcode.

You might notice that the size of the collection is set to hold three Simpson objects. Let’s check this in a detailed way.

The first object in the set will be will be inserted normally:

 new Simpson("Homer"); 

The next object will be inserted normally, as well, because it holds a different value from the previous object:

 new Simpson("Marge"); 

Finally,  the following Simpson object has the same value as the first object. In this case the object won’t be inserted:

 set.add(new Simpson("Homer")); 

כידוע, overridenHomerהאובייקט משתמש בערך hashcode שונה מהאינסטימציה הרגילה Simpson(“Homer”). מסיבה זו, אלמנט זה יוכנס לאוסף:

 overriddenHomer; 

מקש מענה

התשובה המתמודד Java הזה הוא B . התפוקה תהיה:

 true false 3 

אתגר וידאו! ניפוי שגיאות שווה ל- () ולקוד hashcode ()

ניפוי באגים הוא אחת הדרכים הקלות ביותר לקלוט מושגי תכנות באופן מלא תוך שיפור הקוד שלך. בסרטון הזה תוכל לבצע יחד בזמן שאני באגים ולהסביר את Java equals()ו- hashcode()אתגר.