CodeGym /בלוג Java /Random-HE /Java hashCode()
John Squirrels
רָמָה
San Francisco

Java hashCode()

פורסם בקבוצה

עקרון האש

קודם כל, לפני שאנחנו מגדירים את ה-hashcode של Java, אנחנו צריכים להבין מה זה hashing ולמה הוא מיועד. Hash הוא תהליך של החלת פונקציית Hash על נתונים מסוימים. פונקציית Hash היא רק פונקציה מתמטית. אל תדאג בקשר לזה! "מתמטי" לא תמיד אומר "מסובך". כאן זה אומר רק שיש לנו נתונים מסוימים וכלל מסוים שממפה את הנתונים לקבוצת תווים (קוד). לדוגמה, זה יכול להיות צופן הקסדצימלי. יש לנו כמה נתונים בכל גודל בקלט, ומחילים עליו פונקציית hash. בפלט, אנו מקבלים נתונים בגודל קבוע, נניח, 32 תווים. בדרך כלל, סוג זה של פונקציה ממירה פיסת נתונים גדולה לערך מספר שלם קטן. התוצאה של עבודת פונקציה זו נקראת קוד hash. פונקציות Hash נמצאות בשימוש נרחב בהצפנה, וגם בכמה תחומים אחרים. פונקציות Hash יכולות להיות שונות, אבל לכולן יש מאפיינים מסוימים:
  • לאובייקט מסוים יש קוד חשיש מסוים.
  • אם שני אובייקטים שווים, קודי ה-hash שלהם זהים. ההיפך אינו נכון.
  • אם קודי ה-hash שונים, אז האובייקטים אינם שווים בוודאות.
  • לאובייקטים שונים יכול להיות אותו קוד hash. עם זאת, מדובר באירוע מאוד לא סביר. בשלב זה, יש לנו התנגשות, מצב שבו אנחנו יכולים לאבד נתונים.
פונקציית הגיבוב "התקינה" ממזערת את ההסתברות להתנגשויות.

Hashcode ב-Java

ב-Java פונקציית hash מחוברת בדרך כלל לשיטת hashCode() . בדיוק, התוצאה של החלת פונקציית hash על אובייקט היא hashcode. לכל אובייקט Java יש קוד hash. באופן כללי Hash Code הוא מספר המחושב בשיטת hashCode() של Objectהמחלקה. בדרך כלל, מתכנתים עוקפים שיטה זו עבור האובייקטים שלהם וכן קשורים ל- hashCode() השיטה equals() לעיבוד יעיל יותר של נתונים ספציפיים. שיטת hashCode() מחזירה ערך int (4 בתים), שהוא ייצוג מספרי של האובייקט. Hashcode זה משמש, למשל, על ידי אוספים לאחסון יעיל יותר של נתונים ובהתאם, גישה מהירה יותר אליהם. כברירת מחדל, הפונקציה hashCode() עבור אובייקט מחזירה את המספר של תא הזיכרון שבו האובייקט מאוחסן. לכן, אם לא בוצעו שינויים בקוד היישום, הפונקציה אמורה להחזיר את אותו ערך. אם הקוד משתנה מעט, גם ערך ה-hashcode משתנה. למה משמש ה-hashcode ב-Java? קודם כל קודי ג'אווה עוזרים לתוכניות לרוץ מהר יותר. לדוגמה, אם נשווה בין שני אובייקטים o1ומסוג o2כלשהו, ​​הפעולה o1.equals(o2)לוקחת בערך פי 20 יותר זמן מאשר o1.hashCode() == o2.hashCode().

Java שווה()

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

יישום שיטת hashCode()‎

דוגמא

בואו ניצור דמות מחלקה עם שדה אחד - שם . לאחר מכן, אנו יוצרים שני אובייקטים של Character class, character1 ו- charact2 ומגדירים להם את אותו השם. אם נשתמש ברירת המחדל hashCode() ו- equals() של המחלקה Object , בהחלט נקבל אובייקטים שונים, לא שווים. כך עובד hashcode ב-Java. יהיו להם קודי hash שונים מכיוון שהם נמצאים בתאי זיכרון שונים ותוצאת הפעולה equals() תהיה false.
import java.util.Objects;

public class Character {
    private String Name;

    public Character(String name) {
        Name = name;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    public static void main(String[] args) {
        Character character1 = new Character("Arnold");
        System.out.println(character1.getName());
        System.out.println(character1.hashCode());
        Character character2 = new Character("Arnold");
        System.out.println(character2.getName());
        System.out.println(character2.hashCode());
        System.out.println(character2.equals(character1));
    }
}
התוצאה של הפעלת התוכנית:

Arnold
1595428806
Arnold
1072408673
false
שני מספרים בני 10 ספרות בקונסולה הם קודי hash. מה אם נרצה שיהיו חפצים שווים אם יש להם אותם שמות? מה אנחנו צריכים לעשות? התשובה: עלינו לעקוף את שיטות hashCode() ו- equals() של מחלקת Object עבור מחלקת Character שלנו . נוכל לעשות זאת אוטומטית ב-IDEA IDE, פשוט הקש alt + insert במקלדת ובחר Generate -> equals() ו-hashCode() . מהו Java hashCode() - 2במקרה של הדוגמה שלנו יש לנו את הקוד הבא:
import java.util.Objects;

public class Character {
    private String Name;

    public Character(String name) {
        Name = name;
    }

    public String getName() {
        return Name;
    }

    public void setName(String name) {
        Name = name;
    }

    @Override
    public boolean equals(Object o) {
        if (this == o) return true;
        if (!(o instanceof Character)) return false;

        Character character = (Character) o;

        return getName() != null ? getName().equals(character.getName()) : character.getName() == null;
    }

    @Override
    public int hashCode() {
        return getName() != null ? getName().hashCode() : 0;
    }

    public static void main(String[] args) {
        Character character1 = new Character("Arnold");
        System.out.println(character1.getName());
        System.out.println(character1.hashCode());
        Character character2 = new Character("Arnold");
        System.out.println(character2.getName());
        System.out.println(character2.hashCode());
        System.out.println(character2.equals(character1));
    }
}
התוצאה של הפעלת הקוד הזה:

Arnold
1969563338
Arnold
1969563338
true
אז עכשיו התוכנית מזהה את האובייקטים שלנו כשווים ויש להם את אותם קודי hashcode.

דוגמה hashcode של Java:

hashCode() ושווה() משלך

אתה יכול גם ליצור מימושי equals() ו- hashCode() משלך , אבל היזהר וזכור למזער את התנגשויות hashcode. הנה דוגמה לשיטות hashCode() ו- equals() משלנו בכיתה Student :
import java.util.Date;

public class Student {
   String surname;
   String name;
   String secondName;
   Long birthday; // Long instead of long is used by Gson/Jackson json parsers and various orm databases

   public Student(String surname, String name, String secondName, Date birthday ){
       this.surname = surname;
       this.name = name;
       this.secondName = secondName;
       this.birthday = birthday == null ? 0 : birthday.getTime();
   }
//Java hashcode example
   @Override
   public int hashCode(){
       //TODO: check for nulls
       //return surname.hashCode() ^ name.hashCode() ^ secondName.hashCode() ^ (birthday.hashCode());
       return (surname + name + secondName + birthday).hashCode();
   }
   @Override
   public boolean equals(Object other_) {
       Student other = (Student)other_;
       return (surname == null || surname.equals(other.surname) )
               && (name == null || name.equals(other.name))
               && (secondName == null || secondName.equals(other.secondName))
               && (birthday == null || birthday.equals(other.birthday));
   }
}
והכיתה הראשית להדגים את עבודתם:
import java.util.Date;
import java.util.HashMap;
import java.util.Hashtable;

public class Main {
   static HashMap<Student, Integer> cache = new HashMap<Student, Integer>(); // <person, targetPriority>

   public static void main(String[] args) {
       Student sarah1 = new Student("Sarah","Connor", "Jane", null);
       Student sarah2 = new Student("Sarah","Connor", "Jane", new Date(1970, 01-1, 01));
       Student sarah3 = new Student("Sarah","Connor", "Jane", new Date(1959, 02-1, 28)); // date not exists
       Student john = new Student("John","Connor", "Kyle", new Date(1985, 02-1, 28)); // date not exists
       Student johnny = new Student("John","Connor", "Kyle", new Date(1985, 02-1, 28)); // date not exists
       System.out.println(john.hashCode());
       System.out.println(johnny.hashCode());
       System.out.println(sarah1.hashCode());
       System.out.println();
       cache.put(sarah1, 1);
       cache.put(sarah2, 2);
       cache.put(sarah3, 3);
       System.out.println(new Date(sarah1.birthday));
       System.out.println();
       cache.put(john, 5);
       System.out.println(cache.get(john));
       System.out.println(cache.get(johnny));
       cache.put(johnny, 7);
       System.out.println(cache.get(john));
       System.out.println(cache.get(johnny));
   }
}

למה משמש hashcode?

קודם כל קודי hash עוזרים לתוכניות לרוץ מהר יותר. לדוגמה, אם נשווה שני אובייקטים o1ומסוג o2כלשהו, ​​הפעולה o1.equals(o2)לוקחת בערך פי 20 יותר זמן מאשר o1.hashCode() == o2.hashCode(). ב-Java עקרון הגיבוב עומד מאחורי כמה אוספים פופולריים, כגון HashMap , HashSet ו- HashTable .

סיכום

לכל אובייקט Java יש את המתודות hashCode() ו- equals() בירושה ממחלקת Object . כדי לקבל מנגנון שוויון תקין, עדיף שתעקוף את שיטות hashcode() ו- equals() עבור השיעורים שלך. שימוש בקודי hash גורם לתוכניות לרוץ מהר יותר.
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION