המרה כלפי מעלה וכלפי מטה
חלק מהיחידה תכנות מונחה עצמים במסלול ה-Java של Coddy. שיעור 30 מתוך 87.
בשיעור הקודם ראית כיצד משתנה מסוג האב יכול להכיל אובייקט צאצא: Animal myPet = new Dog(). השמה זו נקראת המרה כלפי מעלה (upcasting), והיא מתבצעת אוטומטית כי Dog הוא תמיד Animal.
המרה כלפי מעלה מתקדמת כלפי מעלה בהיררכיית הירושה. היא מתבצעת באופן משתמע ותמיד בטוחה:
Dog dog = new Dog();
Animal animal = dog; // המרה לטיפוס אב - אוטומטיתבעת המרה למחלקת האב, אפשר לגשת רק למתודות שהוגדרו במחלקת האב. המתודות הייחודיות למחלקת הבת נעשות מוסתרות, אף על פי שמתחת לפני השטח האובייקט עדיין מסוג Dog.
המרה כלפי מטה פועלת בכיוון ההפוך, וממירה הפניה למחלקת אב בחזרה לטיפוס של מחלקת בת. לשם כך נדרשת המרה מפורשת, כי היא לא תמיד בטוחה:
Animal animal = new Dog(); // המרה כלפי מעלה
Dog dog = (Dog) animal; // המרה כלפי מטה - נדרשת המרת טיפוס מפורשת
dog.bark(); // כעת אפשר לגשת למתודות של Dogהמרה כלפי מטה היא מסוכנת. אם האובייקט אינו באמת מהסוג שאליו ממירים אותו, Java זורקת ClassCastException בזמן הריצה:
Animal animal = new Cat();
Dog dog = (Dog) animal; // עובר קומפילציה, אבל קורס בזמן ריצה!המהדר לא יכול לזהות את השגיאה הזאת כי הוא רואה רק את הטיפוסים המוצהרים. הטיפוס של האובייקט בפועל ידוע רק כשהתוכנית רצה. בשיעור הבא תלמד איך לבדוק בבטחה את הטיפוס של אובייקט לפני ביצוע המרה כלפי מטה.
אתגר
קלבואו נבנה מערכת נגן מדיה שמדגימה בפועל גם המרת טיפוס כלפי מעלה וגם המרת טיפוס כלפי מטה. תיצור היררכיה של סוגי מדיה ותתרגל המרה בין הפניות למחלקת אב ולמחלקות יורשות.
תארגן את הקוד שלך בארבעה קבצים:
Media.java: צור מחלקת בסיס המשותפת לכל סוגי המדיה. לכל פריט מדיה יש שדהtitle(String). כלול בנאי לאתחול שלו, מתודת getter בשםgetTitle(), ומתודה בשםplay()שמדפיסה:Playing: [title]Song.java: צור מחלקה שיורשת מ-Media. לשירים יש שדה נוסף בשםartist(String). השתמש ב-superלאתחול מחלקת האב. דרוס אתplay()כדי להדפיס:Playing song: [title] by [artist]. הוסף מתודה בשםshowArtist()שמדפיסה:Artist: [artist]Podcast.java: צור מחלקה נוספת שיורשת מ-Media. לפודקאסטים יש שדה בשםepisode(int). דרוס אתplay()כדי להדפיס:Playing podcast: [title] - Episode [episode]. הוסף מתודה בשםshowEpisode()שמדפיסה:Episode: [episode]Main.java: הדגם המרות טיפוס כלפי מעלה וכלפי מטה עם סוגי המדיה שלך. תקבל ארבעה קלטים: שם של שיר, שם של אמן, שם של פודקאסט ומספר של פרק.תחילה, צור Song והמר אותו כלפי מעלה להפניה מסוג Media. קרא ל-
play()באמצעות ההפניה הזו כדי לראות פולימורפיזם בזמן ריצה בפעולה.לאחר מכן, המר את הפניית ה-Media הזו כלפי מטה בחזרה ל-Song וקרא ל-
showArtist()כדי לגשת למתודה הייחודית למחלקה היורשת.לאחר מכן, צור Podcast והמר אותו כלפי מעלה להפניה מסוג Media. קרא ל-
play()באמצעות ההפניה הזו.לבסוף, המר את הפניית ה-Media הזו כלפי מטה בחזרה ל-Podcast וקרא ל-
showEpisode().
תקבל ארבעה קלטים: שם השיר (String), שם האמן (String), שם הפודקאסט (String) ומספר הפרק (int).
הפלט שלך צריך להציג ארבע שורות — שתיים עבור השיר (פלט ההפעלה שלו ופרטי האמן) ושתיים עבור הפודקאסט (פלט ההפעלה שלו ופרטי הפרק). שים לב כיצד המרת טיפוס כלפי מעלה מאפשרת לך להתייחס לסוגי מדיה שונים באופן אחיד, ואילו המרת טיפוס כלפי מטה מאפשרת לך לגשת לתכונות הייחודיות שלהם!
נסו בעצמכם
import java.util.Scanner;
class Main {
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
// קראו את הקלטים
String songTitle = scanner.nextLine();
String artistName = scanner.nextLine();
String podcastTitle = scanner.nextLine();
int episodeNumber = scanner.nextInt();
// TODO: צרו מופע של Song ובצעו לו המרת טיפוס כלפי מעלה להפניה מסוג Media
// TODO: קראו ל-play() דרך ההפניה מסוג Media (מדגים פולימורפיזם)
// TODO: בצעו המרת טיפוס כלפי מטה של ההפניה מסוג Media בחזרה ל-Song
// TODO: קראו ל-showArtist() דרך ההפניה מסוג Song
// TODO: צרו מופע של Podcast ובצעו לו המרת טיפוס כלפי מעלה להפניה מסוג Media
// TODO: קראו ל-play() דרך ההפניה מסוג Media
// TODO: בצעו המרת טיפוס כלפי מטה של ההפניה מסוג Media בחזרה ל-Podcast
// TODO: קראו ל-showEpisode() דרך ההפניה מסוג Podcast
}
}
השיעור הזה כולל חידון קצר. התחילו את השיעור כדי לענות עליו ולעקוב אחרי ההתקדמות.
כל השיעורים ביחידה תכנות מונחה עצמים
1יסודות התכנות מונחה העצמים
קבצים חיצונייםמבוא לתכנות מונחה עצמיםמחלקות לעומת אובייקטיםמילת המפתח thisמתודותשדות (מאפיינים)מתודת הבנאיהעמסת בנאיםחזרה – מחשבון פשוט4ירושה
ירושה בסיסית (extends)מילת המפתח superדריסת מתודות (@Override)שרשור בנאיםהמחלקה Objectירושה יחידה ורב־רמתיתלמה אין ירושה מרובה של מחלקותסיכום – היררכיית עובדים7מתודות מיוחדות ומחלקת Object
מתודת toString()equals() ו-hashCode()מתודת clone()compareTo() ו-Comparableהממשק Comparatorסיכום – מיון מותאם אישית2מצייני גישה ואנקפסולציה
סקירה של רמות הגישהמתודות Getter ו-Setterהסתרת מידעמילת המפתח finalסיכום – מנהל חשבון בנק5פולימורפיזם
יסודות העמסת מתודותדריסת מתודות (בזמן ריצה)המרה כלפי מעלה וכלפי מטההאופרטור instanceofמחלקות ומתודות מופשטותסיכום – מחשבון צורות8מושגי OOP מתקדמים
הרכבה מול ירושהאגרגציה מול הרכבהמחלקות פנימיות, מקוננות ואנונימיותEnums ומתודות של EnumRecords (Java 16+)מחלקות חתומות (Java 17+)3מאפייני מחלקה וחברים סטטיים
משתני מופע לעומת משתנים סטטייםמתודות סטטיותבלוקים סטטייםקבועים (static final)סיכום — מונה ומחלקת עזר6ממשקים ומחלקות מופשטות
מבוא לממשקיםמימוש ממשקיםמימוש של כמה ממשקיםמתודות ברירת מחדל וסטטיות בממשקמחלקות מופשטות לעומת ממשקיםממשקים פונקציונלייםסיכום – מערכת תשלומיםתרגלו בעצמכם: קומפיילר Java אונליין