היי! בשיעורים הקודמים כבר התוודענו בקצרה למושג הירושה. היום, ניגע שוב בנושא הזה, אבל שוב לא לעומק. אנחנו עדיין עומדים לקבל שיעור מפורט יותר על זה בעתיד. היום רק נסתכל במהירות על כמה דוגמאות מעשיות ונכיר מפעיל מעניין בג'אווה.
Inheritance הוא מנגנון תכנות (כולל ב-Java) המאפשר להכריז על מחלקה חדשה על סמך מחלקה קיימת. המחלקה הנגזרת מקבלת גישה לשדות ולשיטות של מחלקת האב. למה שנצטרך את זה? ובכן, תאר לעצמך שאתה צריך ליצור מספר מחלקות רכב בתוכנית: משאית, RaceCar, Sedan, Pickup וכו'. עוד לפני כתיבת קוד כלשהו, אתה יודע בוודאות שלכל המחלקות הללו יש הרבה במשותף: לכל המכוניות יש דגם שם, שנת ייצור, גודל מנוע, מהירות מרבית וכו' (שלא לדבר על העובדה שלכולם יש גלגלים וחלקים אחרים במשותף). במצב זה, אתה יכול:
יְרוּשָׁה
אז מהי ירושה?
- צור שדות אלה בכל מחלקה (הוספת אותם לכל מחלקה חדשה של מכוניות תוך כדי יצירתה)
- הבא את השדות המשותפים לכל המכוניות למחלקה
Car
אב, ולאחר מכן השתמש במילת המפתח extends כדי לגזור את כל המחלקות לסוגים ספציפיים של מכוניות מהמחלקהCar
.
public class Car {
private String model;
private int maxSpeed;
private int yearOfManufacture;
public Car(String model, int maxSpeed, int yearOfManufacture) {
this.model = model;
this.maxSpeed = maxSpeed;
this.yearOfManufacture = yearOfManufacture;
}
}
public class Truck extends Car {
public Truck(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
public class Sedan extends Car {
public Sedan(String model, int maxSpeed, int yearOfManufacture) {
super(model, maxSpeed, yearOfManufacture);
}
}
לכל הפחות, אנו נמנעים משכפול מיותר של קוד (ועלינו לשאוף לכך תמיד בעת כתיבת תוכניות). בנוסף, יש לנו מבנה מחלקה פשוט ומובן, כאשר כל התחומים המשותפים לכל המכוניות מאוחדים למחלקה אחת. אם למשאיות יש תחומים מיוחדים שאין למכוניות אחרות, ניתן להכריז עליהם בכיתה Truck
. כך גם לגבי שיטות. לכל המכוניות יש התנהגות משותפת מסוימת שניתן לתאר באמצעות שיטות, למשל התנעת המכונית, האצה/בלימה וכו'. ניתן לאחד את השיטות הנפוצות הללו למחלקת האב, וכל סוג ספציפי של Car
מכונית יכול להגדיר את הפעולות הייחודיות שלה במחלקות הנגזרות שלהן .
public class Car {
public void gas() {
// Accelerate
}
public void brake() {
// Brake
}
}
public class F1Car extends Car {
public void pitStop() {
// Only race cars make pit stops
}
public static void main(String[] args) {
F1Car formula1Car = new F1Car();
formula1Car.gas();
formula1Car.pitStop();
formula1Car.brake();
}
}
הוספנו לכיתה את השיטות המשותפות לכל המכוניות Car
. אבל, תסתכל על F1Car
המעמד, המייצג מכוניות מרוץ "פורמולה 1". עצירות פיט (עצירות לתחזוקה דחופה של מכונית) נעשות רק במרוצים, אז הוספנו את הפונקציונליות הספציפית הזו למחלקה הנגזרת הרלוונטית. 
מופע של מפעיל
ב-Java, יש אופרטור מיוחד, instanceof , לבדיקה אם אובייקט נוצר על סמך מחלקה מסוימת. זה מחזיר נכון או לא נכון בהתאם לתוצאה של הבדיקה. בוא נראה איך זה עובד באמצעות השיעורים בדוגמה המכונית שלנו:public class Truck extends Car {
public static void main(String[] args) {
Truck truck = new Truck();
System.out.println(truck instanceof Car);
}
}
פלט: true האופרטור instanceof
מחזיר true , מכיוון שיש לנו Truck
אובייקט, וכל המשאיות הן מכוניות. הכיתה Truck
נגזרת מהכיתה Car
. כל המשאיות נוצרות על בסיס ההורה המשותף, Car
הכיתה. תסתכל מקרוב על אופן instanceof
השימוש באופרטור. אתה כותב את זה בלי נקודה, מכיוון שזה אופרטור, לא שיטה ("מופע אובייקט של מחלקה"). בוא ננסה דרך אחרת:
public static void main(String[] args) {
Car car = new Car();
System.out.println(car instanceof Truck);
}
פלט: false המחלקה Car
(ואובייקטי המכונית) אינם נובעים מהמחלקה Truck
. כל המשאיות הן מכוניות, אבל לא כל המכוניות הן משאיות. Car
אובייקטים אינם מבוססים על Truck
המחלקה. עוד דוגמה אחת:
public static void main(String[] args) {
Car car = new Car();
Truck truck = new Truck();
System.out.println(car instanceof Object && truck instanceof Object);
}
פלט: נכון גם כאן ההיגיון פשוט: כל המחלקות ב-Java, כולל המחלקות שאתה יוצר, יורדות מהמחלקה Object
(למרות שאינך כותב "extends Object" - זה כבר מרומז). איך ומתי זה יהיה שימושי? האופרטור instanceof
משמש לרוב בעת עקיפת equals()
השיטה. לדוגמה, כך equals
מיושמת השיטה במחלקה String
:
public boolean equals(Object anObject) {
if (this == anObject) {
return true;
}
if (anObject instanceof String) {
String anotherString = (String) anObject;
int n = value.length;
if (n == anotherString.value.length) {
char v1[] = value;
char v2[] = anotherString.value;
int i = 0;
while (n-- != 0) {
if (v1[i] != v2[i])
return false;
i++;
}
return true;
}
}
return false;
}
לפני השוואה בין a String
לאובייקט שעבר, השיטה בודקת אם האובייקט הוא אפילו מחרוזת? רק אז הוא מתחיל להשוות את המאפיינים של שני האובייקטים. אם הבדיקה הזו לא הייתה קיימת, ניתן היה להעביר כל אובייקט עם שדות ערך ואורך למתודה ולהשוות עם String, וזה יהיה שגוי, כמובן.
GO TO FULL VERSION