Menu
Coddy logo textTech

equals() ו-hashCode()

חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 42 מתוך 87.

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

public class Person {
    private String name;
    private int age;
    
    @Override
    public boolean equals(Object obj) {
        if (this == obj) return true;
        if (obj == null || getClass() != obj.getClass()) return false;
        Person person = (Person) obj;
        return age == person.age && name.equals(person.name);
    }
}

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

בכל פעם שדורסים את equals(), חייבים לדרוס גם את hashCode(). זהו חוזה ב-Java: לאובייקטים שווים חייב להיות אותו קוד גיבוב. אוספים מבוססי גיבוב כמו HashMap ו-HashSet מסתמכים על הכלל הזה כדי לפעול כראוי.

@Override
public int hashCode() {
    return Objects.hash(name, age);
}

מתודת השירות Objects.hash() יוצרת קוד גיבוב מאותם השדות שבהם נעשה שימוש ב־equals(). אם לשני אובייקטים מסוג Person יש אותו שם ואותו גיל, הם ייחשבו שווים ויפיקו קודי גיבוב זהים, וכך תובטח התנהגות עקבית באוספים.

challenge icon

אתגר

קל

בואו נבנה מערכת לניהול רשומות של תלמידים שמממשת נכון שוויון בין אובייקטים. תיצרו מחלקה Student שבה שני תלמידים נחשבים שווים אם יש להם אותו מזהה תלמיד ואותו שם, בלי קשר לשאלה אם הם אותו אובייקט בזיכרון.

תארגנו את הקוד בשני קבצים:

  • Student.java: צרו מחלקה שמייצגת תלמיד ובה שלושה שדות פרטיים: studentId (String), name (String), ו-gpa (double). כללו בנאי לאתחול כל השדות ושיטות getter לכל שדה.

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

    דרסו את השיטה hashCode() באמצעות Objects.hash() עם אותם שדות שבהם השתמשתם ב-equals(). זכרו לייבא את java.util.Objects בראש הקובץ.

  • Main.java: הפיחו חיים במחלקה Student שלכם באמצעות השוואת אובייקטים של תלמידים. תקבלו שש קלטים המייצגים שני תלמידים: תחילה המזהה, השם והממוצע של התלמיד הראשון, ולאחר מכן המזהה, השם והממוצע של התלמיד השני.

    צרו את שני אובייקטי Student, ואז בצעו שלוש השוואות והדפיסו את התוצאות:

    1. הדפיסו Same reference: ולאחריו האם התלמיד הראשון שווה לעצמו (התשובה תמיד צריכה להיות true)
    2. הדפיסו Content equality: ולאחריו האם התלמיד הראשון שווה לתלמיד השני (בהתאם למימוש שלכם של equals)
    3. הדפיסו Hash codes match: ולאחריו האם לשני התלמידים יש אותו קוד גיבוב

תקבלו שש קלטים: המזהה של התלמיד הראשון (String), השם של התלמיד הראשון (String), הממוצע של התלמיד הראשון (double), המזהה של התלמיד השני (String), השם של התלמיד השני (String), והממוצע של התלמיד השני (double).

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

נסו בעצמכם

import java.util.Scanner;

class Main {
    public static void main(String[] args) {
        Scanner scanner = new Scanner(System.in);
        
        // קרא את נתוני התלמיד הראשון
        String id1 = scanner.nextLine();
        String name1 = scanner.nextLine();
        double gpa1 = scanner.nextDouble();
        scanner.nextLine(); // צרוך את התו של סוף השורה
        
        // קרא את נתוני התלמיד השני
        String id2 = scanner.nextLine();
        String name2 = scanner.nextLine();
        double gpa2 = scanner.nextDouble();
        
        // TODO: צור שני אובייקטים מסוג Student באמצעות נתוני הקלט
        
        // TODO: הדפס "Same reference: " ולאחר מכן ציין אם student1 שווה לעצמו
        
        // TODO: הדפס "Content equality: " ולאחר מכן ציין אם student1 שווה ל-student2
        
        // TODO: הדפס "Hash codes match: " ולאחר מכן ציין אם לשני התלמידים יש אותו קוד גיבוב
    }
}
quiz iconבחנו את עצמכם

השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.

כל השיעורים ביחידה תכנות מונחה עצמים

תרגלו בעצמכם: קומפיילר Java אונליין