קודם כל, לפני שאנחנו מגדירים את ה-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.
שני מספרים בני 10 ספרות בקונסולה הם קודי hash. מה אם נרצה שיהיו חפצים שווים אם יש להם אותם שמות? מה אנחנו צריכים לעשות? התשובה: עלינו לעקוף את שיטות hashCode() ו- equals() של מחלקת Object עבור מחלקת Character שלנו . נוכל לעשות זאת אוטומטית ב-IDEA IDE, פשוט הקש alt + insert במקלדת ובחר Generate -> equals() ו-hashCode() . במקרה של הדוגמה שלנו יש לנו את הקוד הבא:
אז עכשיו התוכנית מזהה את האובייקטים שלנו כשווים ויש להם את אותם קודי hashcode.
דוגמה hashcode של Java:
hashCode() ושווה() משלך
אתה יכול גם ליצור מימושי equals() ו- hashCode() משלך , אבל היזהר וזכור למזער את התנגשויות hashcode. הנה דוגמה לשיטות hashCode() ו- equals() משלנו בכיתה Student :
importjava.util.Date;publicclassStudent{String surname;String name;String secondName;Long birthday;// Long instead of long is used by Gson/Jackson json parsers and various orm databasespublicStudent(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@OverridepublicinthashCode(){//TODO: check for nulls//return surname.hashCode() ^ name.hashCode() ^ secondName.hashCode() ^ (birthday.hashCode());return(surname + name + secondName + birthday).hashCode();}@Overridepublicbooleanequals(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));}}
והכיתה הראשית להדגים את עבודתם:
importjava.util.Date;importjava.util.HashMap;importjava.util.Hashtable;publicclassMain{staticHashMap<Student,Integer> cache =newHashMap<Student,Integer>();// <person, targetPriority>publicstaticvoidmain(String[] args){Student sarah1 =newStudent("Sarah","Connor","Jane",null);Student sarah2 =newStudent("Sarah","Connor","Jane",newDate(1970,01-1,01));Student sarah3 =newStudent("Sarah","Connor","Jane",newDate(1959,02-1,28));// date not existsStudent john =newStudent("John","Connor","Kyle",newDate(1985,02-1,28));// date not existsStudent johnny =newStudent("John","Connor","Kyle",newDate(1985,02-1,28));// date not existsSystem.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(newDate(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 גורם לתוכניות לרוץ מהר יותר.
GO TO FULL VERSION