תכנות ג'נרי

LironBar247

New member
תכנות ג'נרי

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

במחלקה PriorityQueueCustomerApplyTest, בשורה הראשונה שבה אני בודקת האם קיימת פניית לקוח מסוים בתור העדיפויות - זוהי אמורה להיות שורה 49 - מודפס לי false במקום true.
ציינתי גם בקוד עצמו את מקום השורה הבעייתית בהערה.
כשדיבגתי שמתי לב שלא נכנסים כלל ל-equals שהגדרתי עבור המחלקה CustomerApply, אלא "נעצרים" ב-equals של PriorityElement. על-אף בחינות מרובות של הקוד, לא הצלחתי להבין מדוע זה קורה.

הדבר היחיד שקצת מעורר את חשדותיי הוא העניין שיש לי שתי מחלקות ג'נריות - PriorityQueue ו-PriorityElement, ואולי, מסיבה כלשהי שאיני מבינה, הם גורמים לדברים להשתבש...

אשמח לכל עזרה או הכוונה :)

 

BravoMan

Active member
שווה לתגלן את השאלה הזו!

למרות שהשאלה לא נשאלה כ"כ טוב, ויש המון חומר לעבור עליו למי שרוצה לפתור אותה, הבעיה המוצגת והפתרון הם נושא מתקדם ומעניין ב-Java, משהו שגם מפתחים וותיקים כמוני צריכים לשים לב אליו, ולקח לי זמן לרדת לשורש העניין.

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

אז, מה קרה כאן?

בבעיה משתתפות 3 מחלקות:
מחלקה PriorityQueue שהיא מחלקת אוסף די רגילה, עם אובייקטים מטיפוס קבוע.
מחלקה PriorityElement שמחזיקה פריט בודד מטיפוס כלשהו (מחלקה גינרית) וניתן להכניס אותה לאוסף (queue)
מחלקה CustomerApply שהיא הטיפוס ש-PriorityElement מחזיק ומנסה להשוות.

השואלת מימשה את המתודה equals ב-PriorityElement וב-CustomerApply.
אבל, היא לא ממשה אותה כ-Override אלא כ-Overload!

למי שלא מכיר:
הדרך הנכונה ב-Java לממש את המתודה equals היא "לדרוס" Override את המתודה המקורית שמוגדרת ב-Object.
כלומר, לא משנה באיזו מחלקה אתם ממשים את המתודה הזו, הפרמטר שהיא מקבלת (אובייקט להשוואה) חייב להיות מטיפוס Object.

אחרת, המתודה שהגדרתם לא תחליף את המתודה המקורית.

מה שהשואלת עשתה נקרא "העמסה" - Overloading.
עבור PriorityElement היא הגדירה equals לקבל PriorityElement ועבור CustomerApply היא הגדירה אותה לקבל CustomerApply.

ומכאן יצא בלגן:
מחלקת האוסף PriorityQueue קראה ל-equals ישירות על משתנה מטיפוס PriorityElement ולכן Java מצה את המתודה המועמסת הכי מתאימה - את זו שהשואלת הגדירה.

אבל, מחלקת PriorityElement קראה ל-equals על משתנה מטיפוס גינרי!

וכאן אנו נתקלים בפרט מימוש שגם אני לא היכרתי, אבל חשוב להכיר:
Java ממשת Generics ע"י erasure כלומר "מחיקה": היא מחליפה כל מקום שבו מופיע טיפוס גינרי, למשל T בטיפוס Object בזמן קומפילציה.

כך, שבזמן ריצה אין חיפוש של מתודות מועמסות.

וזו הסיבה שהשואלת ראתה שמתודה ה-equals במחלקה CustomerApply שלה לא נקראת.

אולי זה חור בהשכלה שלי, אבל לקח לי לא מעט debug וקריאה של ההסבר ב-StackOverfolow כדי להבין למה בחלק מהמקרים זה כן עבד ובחלק לא.

לא רציתי להסתפק ב-"חייבים לדרוס נכון את equals" אלא להבין את החוקיות, ולמדתי משהו מעניין על הדרך.

מקווה שהתשובה הזו תחסוך למישהו את חיטוטים ותהיות...
 
למעלה