Presentation is loading. Please wait.

Presentation is loading. Please wait.

המשך תכנות מונחה עצמים 1. היום בתרגול  הורשה  שיטות מיוחדות  פולימורפיזם 2.

Similar presentations


Presentation on theme: "המשך תכנות מונחה עצמים 1. היום בתרגול  הורשה  שיטות מיוחדות  פולימורפיזם 2."— Presentation transcript:

1 המשך תכנות מונחה עצמים 1

2 היום בתרגול  הורשה  שיטות מיוחדות  פולימורפיזם 2

3 3 הורשה - כללים רשימת כללים להורשה 1. מחלקה יכולה להרחיב (לַרשת) רק מחלקה אחת. (ניתן להשתמש בממשקים אם יש צורך בהתנהגויות מרובות) אופניים עם גלגלי עזר אופנייםמשחקי ילדים

4 4 הורשה - כללים 2. מחלקה B תרחיב את A אם נכון לומר "B הוא סוג של A". ב-Java נכתוב: class B extends A אופני מרוץ אופניים A B

5 5 הורשה - כללים 3. אובייקט מרחיב (מטיפוס B) מכיל בתוכו את האובייקט המורחב (מטיפוס A). 4. A היא ה parent class או ה super class של B B היא ה child class או ה subclass של A אופני מרוץ אופניים A B אופני מרוץ - public void race() אופניים - color = Red - speed = 50 km/h - public void ride()

6 6 הורשה - כללים 5. B יורשת את כל השיטות והמשתנים שאינם private ב-A מלבד הבנאים. לא ניתן לגשת בתוך B לשיטות או שדות פרטיים ב-A על אף שהם קיימים (עבור שיטות נראה דוגמה בהמשך הקורס, כשנדבר על protected) public class Bicycle { private int wheelsNum; } public class TrainingBicycle extends Bicycle { private int trainingWheelsNum; public TrainingBicycle() { wheelsNum=2; trainingWheelsNum = 1; } //  compilation error

7 7 הורשה - כללים 6. בנאים אינם עוברים בהורשה! לכן יש להגדיר בנאים חדשים 7. כשיוצרים אובייקט חדש מסוג B, הבנאי של מחלקה A חייב להיקרא. –ניתן לקרוא לו באופן מפורש, אחרת נקרא באופן אוטומטי הבנאי ללא- פרמטרים של A. –קריאה מפורשת נעשית ע"י super(…). super הינה מלה שמורה בשפת Java,אשר מייצגת את מחלקת האב. public class Bicycle { private int wheelsNum; public Bicycle(int i) { wheelsNum = i; } public class TrainingBicycle extends Bicycle { private int trainingWheelsNum; public TrainingBicycle() { super(2); trainingWheelsNum = 1; } //calls the constructor of Bicycle

8 8 הורשה - כללים מה קורה במקרה זה? public class Bicycle { private int wheelsNum; public Bicycle(int i) { wheelsNum = i; } public class TrainingBicycle extends Bicycle { private int trainingWheelsNum; public TrainingBicycle() { trainingWheelsNum = 1; } זו שגיאת קומפילציה! no empty constructor for Bicycle: Cannot find symbol: constructor Bicycle()

9 9 הורשה - כללים 8. הקריאה ל super חייבת להיות השורה הראשונה בבנאי של B מה קורה במקרה זה? public class Bicycle { private int wheelsNum; public Bicycle(int i) { wheelsNum = i; } public class TrainingBicycle extends Bicycle { private int trainingWheelsNum; public TrainingBicycle() { trainingWheelsNum = 1; super(2); } 1. Cannot find symbol: constructor Bicycle() 2. Call to super must be first statement in constructor הקומפיילר יראה זאת כ- 2 שגיאות קומפילציה!

10 10 הורשה - כללים 9.דריסה – Overriding דריסה תתרחש כאשר מחלקת הבן מגדירה שיטה בעלת חתימה זהה לשיטה המוגדרת במחלקת האב – כאשר מדובר בדריסה, הטיפוס של המופע (instance) – מה שנמצא בקצה החץ בטבלת המשתנים והזיכרון – מגדיר איזו פונקציה תופעל. – במקרים אחרים מופעלת הפונקציה לפי הרפרנס (reference) – מה שרשום כטיפוס המשתנה בטבלת המשתנים – דריסה תתרחש רק בשיטות שאינן private. 10. super - אם רוצים לקרוא באופן מפורש לפונקציה של האב ניתן להשתמש במילה super.

11 11 public class Bicycle { private int wheelsNum; public Bicycle(int i) { wheelsNum = i; } public int countWheels() { return wheelsNum; } public class TrainingBicycle extends Bicycle{ private int trainingWheelsNum; public TrainingBicycle() { super(2); trainingWheelsNum = 1; } public int countWheels() { // overrides countWheels() of Bicycle int regWheelsNum = super.countWheels(); //fetch regular # return trainingWheelsNum + regWheelsNum; //return their sum } TrainingBicycle - trainingWheelsNum=1 - int countWheels() Bicycle - wheelsNum = 2 - int countWheels() דוגמה 1:

12 12 public class Bicycle { private int wheelsNum; public Bicycle(int i) { wheelsNum = i; } public int countWheels() { return wheelsNum; } public class TrainingBicycle extends Bicycle{ private int trainingWheelsNum; public TrainingBicycle() { super(2); trainingWheelsNum = 1; } public void countWheels() { int regWheelsNum = super.countWheels(); System.out.println(trainingWheelsNum + regWheelsNum); } -לא ניתן לדרוס שיטה עם חתימה זהה וטיפוס החזרה שונה: דוגמה 2: שגיאת קומפילציה The return type is incompatible with Bicycle.countWheels() TrainingBicycle - trainingWheelsNum=1 - int countWheels() Bicycle - wheelsNum = 2 - void countWheels()

13 13 public class Bicycle { private Object wheelsNum; public Bicycle(Object i) { wheelsNum = i; } public Object countWheels() { return wheelsNum; } public class TrainingBicycle extends Bicycle{ private int trainingWheelsNum; public TrainingBicycle() { super(2); trainingWheelsNum = 1; } public String countWheels() { Object regWheelsNum = super.countWheels(); return regWheelsNum.toString(); } -לא ניתן לדרוס שיטה עם חתימה זהה וטיפוס החזרה שונה: דוגמה 2: הערה: זה חוקי כאשר טיפוס ההחזרה הוא אובייקט ויורש מטיפוס ההחזרה של השיטה הנדרסת. TrainingBicycle - trainingWheelsNum=1 - Object countWheels() Bicycle - wheelsNum = 2 - String countWheels()

14 14 הורשה - כללים 11. ניתן ליצור הירארכיה בעזרת הורשה, כך שמחלקת בן של מחלקה אחת יכולה להיות מחלקת אב של מחלקה אחרת. אופניים אופניים עם גלגלי עזר אופני מרוץאופני הרים מושלגים

15 15 הורשה - כללים 12. כל מחלקה מרחיבה בצורה ישירה או עקיפה את המחלקה Object, והיא השורש בהירארכית הירושה. Object אופניים אופניים עם גלגלי עזר אופני מרוץאופני הרים מושלגים

16 תרגיל 1- מעקב public class X { private int num; private char c; public X() { this.num=2; this.c='A'; } public X(int n) { this.num=n; this.c='B'; } public X(int n, char ch) { this.num=n; this.c=ch; } public X(X other) { this.num=other.num; c=other.c; } public int getN() { return this.num; } public char getCh() { return this.c; } public void inc() { this.num++; this.c++; } public String toString() { String s = ""; for(int i = 0; i < this.num; i++) s = s + this.c; return s; }

17 public class Y extends X { private X x; public Y() { super(); x = new X(); } public Y(int n) { super(n); x = new X(); } public Y(X other) { super(); x = new X(other); } public Y(X other, int n) { super(other); x = new X(n); } public void inc() { this.x.inc(); } public X makeA() { return new X(one(this.x.getN(), this.getN()), one(this.x.getCh(), this.getCh())); } private int one(int n, int m) { if(n > m) return n; return m; } private char one(char ch1, char ch2) { if(ch1 < ch2) return ch1; return ch2; } public String toString() { return this.x.toString(); } }

18 public class Test51 { public static void main(String[ ] args) { X a1 = new X(3,'C'); X a2 = new X(4); Y b1 = new Y(a1); a1.inc(); System.out.println(a1); System.out.println(a2); System.out.println(b1); } What is the output? EEEEE BBBB CCC

19 2. Tracing public class X { private static int numX = 0; private int m1; private int m2; public X(int m1, int m2) { this.m1 = m1; this.m2 = m2; this.numX++; System.out.println("X(" + m1 + "," + m2 + "),#" + numX); }

20 public class Y extends X { private static int numY = 0; private double db; public Y(double db, int x) { super(x,x); this.db = db; numY++; System.out.println("Y(" + db + "," + x + "),#" + numY); } public Y(double db, int x, int y) { super(x,y); this.db = db; numY++; System.out.println("Y(" + db + "," + x + "),#" + numY); }

21 public class Z { private static int numZ = 0; private Z aa; private X bb; public Z(Z aa, X bb) { this.aa = aa; this.bb = bb; numZ++; System.out.println("Z Constructor, #" + numZ); } public class Test52 { public static void main(String[] args) { X x1 = new X(2,3); X x2 = new Y(1.5, 6); X x3 = new Y(2.3, 8, 9); Z z4 = new Z(null, x1); Z z5 = new Z(z4, x3); } What is the output?

22 Output X(2,3),#1 X(6,6),#2 Y(1.5,6),#1 X(8,9),#3 Y(2.3,8),#2 Z Constructor, #1 Z Constructor, #2

23 23 המחלקה Object במחלקה Object מוגדרים מימושי ברירת המחדל לשיטות המשותפות לכל האובייקטים. למשל... public String toString() כאשר ממשנו שיטה זו במחלקות שייצרנו ביצענו דריסה לשיטת ברירת המחדל שירשנו מהמחלקה Object. שיטה משותפת נוספת הינה public boolean equals(Object obj) אשר מבצעת השוואה לוגית בין שני אובייקטים (כמו שראינו ב- String). שימו לב כי שוויון לוגי אינו בהכרח השוואה של כל שדות האובייקט.

24 שיטות משותפות לכל האובייקטים: toString עד עתה כשרצינו להדפיס ערך כלשהו השתמשנו בפונקציה מהמשפחה של System.out.print כיצד נוכל להדפיס אובייקט מסוג Complex? ב- Java לכל אובייקט יש שיטה בשם toString, המחזירה String כמו שהמתכנת של המחלקה מחליט 24 public class Point{ public double x; public double y; public String toString() { return "(" + x + ", " + y + ")"; }

25 כעת, כשנדפיס אובייקט מסוג Point (באופן הבא): יודפס על המסך: שימו לב כי ניתן היה (אך לא חובה) לקרוא לשיטה כך: במקרה הראשון, הפונקציה println מפעילה את שיטת ה toString של האובייקט 25 Point p1 = new Point(5, 7); System.out.println(p1); (5.0, 7.0) שיטות משותפות לכל האובייקטים: toString Point p1 = new Point(5, 7); System.out.println(p1.toString());

26 נרצה לממש את השיטה equals עבור Point : מה יקרה כאשר other הוא null ? שגיאה בזמן ריצה: NullPointerException השיטה equals public class Point { public double x; public double y; //... public boolean equals(Object other) { boolean ans; Point otherPoint = (Point)other; ans = (x==otherPoint.x) && (y==otherPoint.y); return ans; } } 26

27 נרצה לממש את השיטה equals עבור Point : מה יקרה כאשר other הוא אינו מטיפוס Point ? שגיאה בזמן ריצה: ClassCastException השיטה equals public class Point { public double x; public double y; //... public boolean equals(Object other) { boolean ans; Point otherPoint = (Point)other; ans = (x==otherPoint.x) && (y==otherPoint.y); return ans; } 27

28 נרצה לממש את השיטה equals עבור Point : השיטה equals public class Point { public double x; public double y; //... public boolean equals(Object other) { boolean ans = false; if(other instanceof Point) { Point otherPoint = (Point)other; ans = (x==otherPoint.x) && (y==otherPoint.y); } return ans; } 28 מחזיר true רק כאשר other אינו null ומטיפוס Point

29 נרצה לממש את השיטה equals עבור Circle: השיטה equals public class Circle{ public Point center; public double radius; //... public boolean equals(Object other) { boolean ans = false; if(other instanceof Circle) { Circle otherCircle = (Circle)other; ans = (radius==otherCircle.radius) && (center.equals(otherCircle.center)); } return ans; } } 29

30 אם לא היינו ממשים את (מבצעים דריסה של) השיטה equals במחלקה Point, בעת הקריאה לשיטה equals היינו פונים לשיטה equals הממומשת ב Object אשר משווה כתובות. equals השיטה 30 public boolean equals(Object other){ return this == other; } השוואה בין כתובות (הערך בטבלת המשתנים)

31 אם לא היינו ממשים את (מבצעים דריסה של) השיטה equals במחלקה Point, בעת הקריאה לשיטה equals היינו פונים לשיטה equals הממומשת ב Object אשר משווה כתובות. equals השיטה 31 public boolean equals(Object other){ return this == other; } ?? מה יקרה אם נגדיר עבור מחלקה Point את השיטה הבאה: ?? public boolean equals(Point other) !! לא ביצענו דריסה של השיטה equals של מחלקת האב Object, מאחר והחתימה שונה.

32 32 Overriding ( דריסה ) vs Overloading ( העמסה ) –העמסה היא כאשר ישנן מספר הגדרות לפונקציה בעלת אותו שם אך עם פרמטרים שונים באותה המחלקה. –דריסה היא הגדרה של שתי שיטות בעלות חתימה זהה, אחת במחלקת האב ואחת במחלקת הבן. –העמסה מאפשרת פעולה דומה עבור data שונה –דריסה מאפשרת לבצע פעולה דומה עבור טיפוס אובייקט שונה.

33 פולימורפיזם (רב צורתיות) התייחסות לעצמים שונים (instance) כדברים דומים (reference) בעלי מכנה משותף. אם נרצה למשל להחזיק מערך של ספרים, אשר יוכל להחזיק ספרים מסוגים שונים, נוכל להגדיר מערך של מצביעים (reference) מטיפוס Book. משתנה (מצביע) מטיפוס מסוים יכול להצביע על כל אובייקט שטיפוסו הוא צאצא של טיפוס זה. לכן, מערך של מצביעים מטיפוס Book יוכל להצביע על אובייקטים מטיפוסים שיורשים את Book. 33

34 34 Book DictionaryCookbook public class Book { private String name; private int pages; public Book(String name, int p){ this.name = new String(name); this.pages = p; } public String getName(){ return this.name; } public void message() { System.out.println(this.name +": " + this.pages + " pages"); }

35 35 Book DictionaryCookbook /* A Dictionary is a kind of Book with definitions */ public class Dictionary extends Book { private int definitions; public Dictionary(String name, int pages, int defs) { super(name, pages); this.definitions = defs; } public void message() { System.out.println(getName() + ": " + definitions + " definitions"); } public int getDefinitions(){ return this.definitions; }

36 36 Book DictionaryCookbook /* A Cook Book is a kind of Book with recipes */ public class Cookbook extends Book { private int recipes; public Cookbook(String name, int pages, int recipes) { super(name, pages); this.recipes = recipes ; } public void message() { System.out.println(getName() + ": " + this.recipes + " recipes "); }

37 שימוש בפולימורפיזם התייחסות לספרים שונים באופן אחיד לפי יכולות מחלקת האב: books Output Webster: 45056 definitions Naked Chef: 50 recipes War and Peace: 1000 pages 37 public static void main(String[] args) { Book [] books = new Book[3]; // new above is for the array not Book objects books[0] = new Dictionary("Webster“, 690, 45056); books[1] = new Cookbook("Naked Chef“, 100, 50); books[2] = new Book("War and Peace“, 1000); for (int i=0; i<books.length; i=i+1) books[i].message(); }

38 שימוש בפולימורפיזם התייחסות לספרים שונים באופן אחיד לפי יכולות מחלקת האב: public static void main(String[] args) { Book [] books = new Book[3]; // new above is for the array not Book objects books[0] = new Dictionary("Webster“, 690, 45056); books[1] = new Cookbook("Naked Chef“, 100, 50); books[2] = new Book("War and Peace“, 1000); books[0].getDefinitions(); // what would this line do ? } books // compilation error - no getDefinitions() for Book בעזרת Casting שימו לב: תכנון נכון של המחלקות יכלול דריסת פונקציות במקום Casting איך ניתן בכל זאת להפעיל שיטה ספציפית? 38 ((Dictionary)books[0]).getDefinitions();

39 פולימורפיזם הינו "חד-כיווני" משתנה מטיפוס Cookbook לא יכול להכיל אובייקט מטיפוס Book. (כי טיפוס מחלקת האב הוא כללי יותר) השורה: Cookbook deserts = new Book("War and Peace“, 1000) תיתן שגיאת קומפילציה 39 Book DictionaryCookbook


Download ppt "המשך תכנות מונחה עצמים 1. היום בתרגול  הורשה  שיטות מיוחדות  פולימורפיזם 2."

Similar presentations


Ads by Google