1 / 35

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

המשך תכנות מונחה עצמים. תרגול מס' 9. היום בתרגול. this Shallow Copy, Deep Copy ממשקים חריגות ( Exceptions ). תזכורת: מחלקות ואובייקטים. הנה המחלקה MyString :. public class MyString { //class fields private char [] elements ; private int length ; //class method

kendis
Download Presentation

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

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. המשך תכנות מונחה עצמים תרגול מס' 9

  2. היום בתרגול • this • Shallow Copy, Deep Copy • ממשקים • חריגות (Exceptions)

  3. תזכורת: מחלקות ואובייקטים • הנה המחלקה MyString: publicclass MyString { //class fields private char[] elements; private intlength; //class method publicint length(){ returnlength; } } שדות – מייצגים מצב של האובייקט שיטה – מתארת התנהגות של האובייקט

  4. תזכורת: מחלקות ואובייקטים • על מנת ליצור אובייקט מסוג MyString, נשתמש במילה new: • אך כיצד ניתן לשים ערכים בתוך המחרוזת שלנו? • לשם כך נגדיר בנאי, שבעזרתו נאתחל את שדה האובייקט MyString s = new MyString();

  5. תזכורת: בנאי (constructor) • בנאי – שיטה מיוחדת עבור מחלקה שתפקידה לייצר אובייקט ולאתחל את שדותיו publicclass MyString { //class fields private char[] elements; private intlength; //constructor with a parameter public MyString(char[] otherElements){ length = otherElements.length; elements = newchar[length]; for (int i = 0; i < otherElements.length; i++) { elements[i] = otherElements[i]; } } ... } השם זהה לשם המחלקה ואין ערך החזרה

  6. this • ראינו כי ניתן להגדיר מספר בנאים למחלקה בעזרת העמסה (Overloading) • ניתן לקרוא מבנאי אחד לבנאי אחר בעזרת המילה השמורה: • לדוגמה: • הקריאה חייבת להתבצע בשורה הראשונהשל הבנאי this public MyString(MyString other){ this(other.elements); } מה היתרון בשימוש בדרך זו? ( )

  7. this • דוגמה נוספת: מה עושה הבנאי השני? publicclass MyString{ privatechar[] elements; privateint length; public MyString(String s) { … } public MyString() { this(""); … } }

  8. this • ניתן להשתמש ב - this על מנת להבדיל בין שדה לבין פרמטר או משתנה לוקאלי בעלי אותו שם. לדוגמה: בעזרת האופרטור (.) publicclass MyString{ private char[] elements; private intlength; public MyString(char[] elements, int length) { this.length = length; this.elements = newchar[this.length]; for (int i = 0; i < this.length; i=i+1) this.elements[i] = elements[i]; } }

  9. תזכורת • תזכורת (מההרצאות) – המחלקות Point ו- Circle: publicclass Point { public doublex; public doubley; public Point() { x = 0; y = 0; } public Point(Point p) { x = p.x; y = p.y; } } בנאי חסר פרמטרים בנאי מעתיק

  10. תזכורת publicclass Circle{ public Point center; public double radius; //constructors public Circle() { center = new Point(); radius = 0; } public Circle(Point cen, double rad) { center = new Point(cen); if (rad >= 0) radius = rad; else rad = 0; } … }//Circle בנאי חסר פרמטרים בנאי המקבל את כל השדות

  11. Deep Copy ו- Shallow Copy • בנאי מעתיק אפשרי ל- Circle: • מה יקרה אם נבצע את הפעולות הבאות: • הבנאי המעתיק משתמש בגישת ה- Shallow Copy. public Circle(Circle other) { center = other.center; radius = other.radius; } Copy constructor publicstaticvoid main(String[] args){ Circle circ1 = new Circle(); Circle circ2 = new Circle(circ1); circ2.center.x = 4; }

  12. Deep Copy ו- Shallow Copy • בנאי מעתיק אפשרי ל- Circle: • מה יקרה עכשיו אם נבצע את הפעולות הבאות: • הבנאי המעתיק משתמש בגישת ה- Deep Copy. public Circle(Circle other) { center = new Point(other.center); radius = other.radius; } publicstaticvoid main(String[] args){ Circle circ1 = new Circle(); Circle circ2 = new Circle(circ1); circ2.center.x = 4; }

  13. ממשקים • ממשק מייצג רעיון מופשט. • הממשק (interface) הינו כלי ב-Java למימוש עיקרון ההפרדה בין הכרזה למימוש. • מבחינת המתכנת, ממשק הוא הצהרת כוונות או הבטחה שצריך למלא. ממשק קובע את הפונקציונאליות המשותפת לכל המחלקות המממשות אותו. אוניברסיטת בן גוריון - מבוא למדעי המחשב

  14. ממשקים – כללים בסיסיים הצהרה על ממשק: publicinterface<name> { <methods list> } • ממשקים מתארים שיטות (ציבוריות) ללא ישומן. • כל השיטות בממשק הן ציבוריות (public) - גם אם לא הוגדרו כך במפורש • הגדרת שיטה כפרטית בממשק היא טעות קומפילציה. הערה חשובה: המשתמש במחלקה המממשת ממשק אינו יכול לדעת את פרטי המימוש של השיטות, ואפילו רצוי שלא יצטרך לחשוב עליהם כדי שיוכל להתרכז במשימה שלפניו ולטפל בה ברמת מופשטות מתאימה.

  15. ממשקים – כללים בסיסיים לדוגמה: publicinterfacePredator { publicboolean chasePrey(Prey p); publicvoid eatPrey(Prey p); } • ממשקים מתארים שיטות (ציבוריות) ללא ישומן. • כל השיטות בממשק הן ציבוריות (public) - גם אם לא הוגדרו כך במפורש • הגדרת שיטה כפרטית בממשק תגרום לטעות קומפילציה.

  16. ממשקים – כללים בסיסיים • ממשק, בדומה למחלקה, מגדיר טיפוס.שדות, משתנים ופרמטרים יכולים להיות מוגדרים להיות מסוג ממשק.למשל, ניתן להצהיר על משתנהx להיות מסוג Predator: Predator x; • לא ניתן ליצור אובייקט מממשק. למשל: x = new Predator(); // will not compile !!!

  17. ממשקים – כללים בסיסיים • ניתן להצהיר על מחלקה כמימוש של ממשק כך: class Tiger implements Predator • מחלקה כזו צריכה לממש את כל שיטות הממשק (שגיאת קומפילציה). יוצאות מן הכלל הזה הן מחלקות אבסטרקטיות, עליהן נדבר בהמשך הקורס. • מחלקה יכולה לממש יותר מממשק אחד! – נראה דוגמה בהמשך

  18. publicinterfacePredator { public boolean chasePrey(Prey p); public void eatPrey(Prey p); } publicclassTigerimplementsPredator { publicboolean chasePrey(Prey p) { // code to chase prey p (specifically for a tiger) return runAfterPrey(p); } publicvoid eatPrey (Prey p) { // code to eat prey p (for a tiger) chew(p); swallow(p); } ... }

  19. publicinterfacePredator { public boolean chasePrey(Prey p); public void eatPrey(Prey p); } publicclassSharkimplementsPredator { publicboolean chasePrey(Prey p) { // code to chase prey p (specifically for a shark) return swimAfterPrey(p); } publicvoid eatPrey (Prey p) { // code to eat prey p //(specifically for a shark) bite(p); swallow(p); } }

  20. "טרף" הוא גם כן תאור כללי של יצור, המסוגל לבצע מספר פעולות בסיסיות. גם לו יהיה ממשק: publicinterfacePrey { publicboolean isAlive(); publicvoid die(); publicvoid runAway(); } • דוגמאות למחלקות שעשויות לממש "טרף": publicclassFrogimplementsPrey { publicvoid jump() { ... } publicvoid runAway() { ... } ... } publicclassDeerimplementsPrey { ... }

  21. כריש הוא טורף וגם נמר הוא טורף. • בזכות הממשק המשותף אותו הם ממשים, אנחנו יכולים למשל, להחזיק מערך של טורפים ולהפעיל פעולות משותפות על כל אחד מהאיברים במערך. Predator[] preds = new Predator[3]; preds[0] = new Tiger(); preds[1] = new Shark(); preds[2] = new Shark(); Prey froggy = new Frog(); for (int i=0; i<preds.length && froggy.isAlive(); i=i+1) { froggy.runAway(); if (preds[i].chasePrey(froggy)) preds[i].eatPrey(froggy); } • ניתן לראות שיצרנו גם טרף – צפרדע, שנרדף ע"י הכרישים והנמר. מיד נראה מה טרף מסוגל לבצע, כלומר כיצד הוגדר ממשק של טרף – interface Prey. האם ניתן היה להפעיל: froggy.jump() ?

  22. אך קודם נראה דוגמה כיצד ניתן לקבל טורף וטרף כפרמטר לפונקציה: publicstaticvoidsimulateChase(Predator predat, Prey prey) { prey.runAway(); if (predat.chasePrey(prey)) predat.eatPrey(prey); } • אנחנו יכולים להפעיל את הפעולות שטורף וטרף יודעים לעשות, למרות שאיננו יודעים איזה טורף או טרף קיבלנו בקריאה לפונקציה.

  23. המשך Shark sharky1 = new Shark(); Frog kermit1 = new Frog(); simulateChase(sharky1, kermit1); שימו לב, ניתן גם לרשום: Predator sharky2 = new Shark(); Prey kermit2 = new Frog(); simulateChase(sharky2, kermit2); •טיפוס המשתנה (reference type) קובע אילו שיטות חוקיות לביצוע עבור המשתנה (נבדק בזמן הידור). •טיפוס האובייקט ((instance type בזיכרון שעליו מצביע המשתנה בזמן הריצה קובע איזו שיטה תופעל (כלומר, מאיזו מחלקה מממשת).

  24. ניתן, כמובן, להוסיף פעולות (שיטות) ומצב (שדות) למחלקות השונות, ללא קשר לממשק אותן ממשות. לדוגמה: publicclassSharkimplementsPredator { private String name; privateintnumOfTeeth; public Shark(String name) { this.name = name; numOfTeeth = 3000 + (int)(Math.random()*1000); } privatevoidswallow(Prey p) { p.die(); } publicintgetNumOfTeeth() { returnnumOfTeeth; } publicvoidswimForFun() { ... } publicvoid eatPrey (Prey p) { bite(p); swallow(p); } ... }

  25. מימוש מספר ממשקים • ניתן לממש יותר מממשק אחד. • על המחלקה המיישמת לממש את הפונקציות של כל הממשקים. • אם מחלקה מיישמת שני ממשקים בעלי שיטה בעלת שם זהה נניח foo אז: • אם לשתי ה foo יש חתימה שונה אז המחלקה המיישמת חייבת לממש את שתיהן. • אם לשתי ה foo יש אותה חתימה ואותו טיפוס מוחזר אז המחלקה מיישמת רק foo אחד. • אם לשתי ה foo יש אותה חתימה אך טיפוס מוחזר שונה - טעות קומפילציה. (לא ניתן לממש את שני הממשקים יחד). • עד עתה חשבנו על צפרדע כטרף. אבל ניתן לחשוב עליו גם כטורף (זבובים יהיו הטרף שלו במקרה זה) publicclassFrogimplementsPrey, Predator { publicboolean chasePrey(Prey p) { ... } publicvoid eatPrey (Prey p) { ... } ... }

  26. לא לא כן האם ניתן היה להגדיר את sharky כ-Predator? האם ניתן היה להגדיר את kermit כ-Prey? האם ניתן היה להגדיר את bzzit כ-Prey? כעת הצפרדע יכולה לבצע את שני התפקידים: Shark sharky = new Shark(); Frog kermit = new Frog(); Fly bzzit = new Fly(); simulateChase(sharky, kermit); if(kermit.isAlive()) simulateChase(kermit, bzzit); sharky.swimForFun(); הערה: אף צפרדע (או זבוב) לא נפגע בהכנת התרגול

  27. חריגות (Exceptions) חריגה היא אירוע המתרחש במהלך תוכנית המפר את תהליך הריצה הנורמאלי של פקודות התוכנית לעיתים חריגות מתרחשות בגלל תקלות בלתי צפויות, כגון בעיה בקובץ אליו כותבים (למשל אין הרשאות כתיבה), ולעיתים בגלל תקלות תוכנה, כגון שליחת פרמטר לא מתאים לפונקציה

  28. בעצם כבר נתקלנו ב-Exceptions Runtime Exceptions IndexOutOfBoundsException: חריגה ממערך NullPointerException: ניסיון לפעול על משתנה שאינו פרימיטיבי בעל ערך null

  29. Throw Exceptions publicvoid setChar(int index, char ch) { if (this.length <= index || index < 0) { thrownew RuntimeException("Index out of bound"); } else { this.elements[index] = ch; } } publicstaticvoid main(String[] args) { MyStringstr = newMyString("Hello world"); str.setChar(-1, '!'); } Exception in thread "main" java.lang.RuntimeException: Index out of bound at MyString.setChar(MyString.java:26) at Main.main(Main.java:35)

  30. כבר נתקלנו ב-RuntimeExceptions וראינו כי ניתן לזרוק RuntimeException באמצעות throw ArithmeticException: ניסיון חלוקה באפס IndexOutOfBoundsException: חריגה ממערך NullPointerException: ניסיון לפעול על משתנה שאינו פרימיטיבי בעל ערך null

  31. Throw RuntimeException publicclass Car { privatefinalint MAX_SPEED = 210; privatefinalint MIN_SPEED = -20; privateint speed; … publicvoidsetSpeed(int speed){ if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED)) this.speed= speed; else thrownewRuntimeException(“Illegal speed”); } } publicstaticvoid main(String[] args) { Car car = new Car(); car.setSpeed(300); } Output: Exception in thread "main" java.lang.RuntimeException: Illegal Speed at Car.setSpeed(Car.java:11) at Car.main(Car.java:17)

  32. סוגי Exceptions Object Exception IOException RuntimeException NullPointerException

  33. Exception • ניתן לייצר חריגהע"י פקודת throwהמייצרת את אירוע החריגה. • ישנן שתי דרכים לטפל בחריגה: • לתפוס את ה- Exception על ידי שימוש במילים השמורות tryו-catch • להעביר את ה- Exception הלאה על ידי שימוש במילה השמורה throwsבכותרת הפונקציה שאנו כותבים. (טיפול בחריגות לא הכרחי עבור (RuntimeExceptions

  34. Throw and Catch Exceptions publicclass Car { privatefinalint MAX_SPEED = 210; privatefinalint MIN_SPEED = -20; privateint speed; … publicvoidsetSpeed(int speed) throws Exception { if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED)) this.speed = speed; else thrownew Exception(“Illegal speed”); } } publicstaticvoid main(String[] args) { Car car = new Car(); car.setSpeed(100); } Compilation Error

  35. Throw and Catch Exceptions publicclass Car { privatefinalint MAX_SPEED = 210; privatefinalint MIN_SPEED = -20; privateint speed; … publicvoidsetSpeed(int speed) throws Exception { if ((speed >= MIN_SPEED) && (speed <= MAX_SPEED)) this.speed = speed; else thrownew Exception(“Illegal speed”); } } publicstaticvoid main(String[] args) { Car car = new Car(); try{ car.setSpeed(300); System.out.println("Broke the speed limit !"); } catch(Exception e){ System.err.println("Caught Exception: "+e.getMessage()); } System.out.println("Current speed is "+car.getSpeed()+” km/h); } Output: Caught Exception: Illegal Speed Current speed is 0 km/h

More Related