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


פורסם ב 15/05/2010 ע"י האקדמיה לפיתוח לאנדרואיד

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

פונקציות

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

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

1. שם הפונקציה: שם לוגי אשר יזהה את הפונקציה ובעזרתו ניקרא לה. שם הפונקציה יכול להיות כל דבר שנרצה, אך תמיד נדאג לתת לו שם בעל משמעות המייצג את מה שהפונקציה בעצם עושה.

2. פרמטרים (קלט): כל פונקציה, בהגדרה, יכולה לקבל בין אפס ל X (כלומר אין סוף) משתנים, המכילים נתונים איתם הפונקציה יכולה לעבודה.

3. טיפוס הפונקציה (פלט): הפונקציה עצמה מחזירה ערך המהווה את התוצאה של הפונקציה. הערך יכול להשתנות אך הטיפוס שלו (integer, double, String וכו…) חייב להיות קבוע מראש.

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

בואו נראה דוגמא לפונקציה:

[sourcecode language="java"]
int GetBiggerNumber(int x, int y)
{
if (x > y)
return x;
else
return y;
}
[/sourcecode]

בקטע קוד זה, הגדרנו פונקציה חדשה בשם GetBiggerNumber אשר מקבלת 2 פרמטרים מסוג int (משתנה x ומשתנה y) ומחזירה ערך מסוג int למי שקרא לה.
כל זה מתואר בשורה מספר 1, כאשר שורות 2 עד 7 הן בעצם קוד הפונקציה עצמה.
שימו לב לתיאור מדוייק יותר של שורה מספר 1:

הסבר על מבנה הפונקציה

פקודה נוספת אליה ארצה להפנות את תשומת ליבכם, היא הפקודה return שנמצאת בשורות 4 ו- 6. כאשר המחשב נתקל בתוך הפונקציה בפקודה return, הוא בעצם מפסיק להריץ את קוד הפונקציה ומחזיר את הערך שמופיע אחרי ה return בתור תוצאת הפונקציה (פלט הפונקציה).
שימו לב כי בשורות 4 ו- 6 אנחנו מחזירים את x או את y, אשר הם מטיפוס int, כפי שהגדרנו בפלט הפונקציה בשורה 1. באם היינו מנסים להחזיר משתנה או טיפוס אחר (לדוגמא, אם היינו כותבים return false), המחשב היה נותן הודעת שגיאה וזאת כי false הינו מסוג boolean ולא int.

לפי קטע הקוד המופיע בשורות 2 עד 7, אפשר לראות שהפונקציה בודקת האם x גדול מ y (שורה 3) ואם הוא אכן גדול יותר, היא מחזירה אותו (שורה 4). אם הוא לא גדול יותר (שורה 5), היא מחזירה את y (שורה 6).
כלומר מטרת הפונקציה היא לקבל 2 ערכים מסוג int ולהחזיר את הגדול בינהם. מי מכם שקרא את שם הפונקציה (GetBiggerNumber) יכל לדעת זאת גם מבלי לקרוא את קוד הפונקציה ולחסוך זמן יקר, ומכאן ניתן להבין מדוע חשוב תמיד לתת לפונקציות שמות משמעותיים.

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

אנדינקודה חשובה מאד פרופסור! תודה על ההערה.
אז איך בעצם קוראים לפונקציות? שימו לב לקטע הקוד הבא:

[sourcecode language="java"]
int GetBiggerNumber(int x, int y)
{
if (x > y)
return x;
else
return y;
}

int x = GetBiggerNumber(10, 20);
int y = GetBiggerNumber(281, 198);

System.out.println(x);
System.out.println(y);

[/sourcecode]

שורות 1 עד 7 הן הגדרת הפונקציה (זהות לקטע קוד העליון).
אך שימו לב לשורה 9. שורה זאת נמצאת מחוץ לבלוק הפונקציה ובה אנו מגדירים משתנה חדש בשם x מסוג int, אשר מקבל את הערך (פלט) שחוזר מהפונקציה GetBiggerNumber, שמקבלת בעצמה 2 ערכים מסוג int (המספר 10 והמספר 20).
בדומה לשורה זאת, שורה 10 מגדירה משתנה בשם y ואליו נכנס ערך שחוזר מאותה פונקציה, רק שהפעם הערכים שהפונקציה מקבלת הינם 281 ו- 198.

עכשיו, שימו לב:

1. קטע הקוד של הפונקציה כתוב רק פעם אחת, אך אנחנו משתמשים בו פעמיים (בשורות 9 ו 10) ונוכל לשוב ולהשתמש בו ככל שנרצה בעתיד. איזה חיסכון!

2. שמות המשתנים בהם השתמשנו חוזרים על עצמם, אך המחשב אינו מתבלבל. כלומר עצם העובדה שהגדרנו משתנה בשם x בתוך הפונקציה (כקלט במקרה הזה) אינו "מתערבב" עם המשתנה x שמחוץ לפונקציה. המחשב יודע להפריד את המשתנים שבתוך הפונקציה עם אלה שבחוץ ובעצם מתייחס לבלוק הפונקציה (שורות 2 עד 7) כקטע קוד עצמאי ונפרד.

בשורות 12 ו 13 אנחנו מדפיסים את הערך של x ושל y (החיצוניים לפונקציה).
מה לדעתכם יודפס בפועל?
אם כתבתם שיודפס 20 ומתחתיו 281, אתם צודקים.

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

שימו לב! לא תוכלו להריץ את דוגמאות הקוד שניתנו עד כה בתוך ה- Eclipse שהפעלנו בשבוע שעבר וזאת בגלל שג'אווה היא שפה מונחית עצמים ומכאן שאת הפונקציות חייבים לכתוב בתוך עצם (אובייקט) מסויים.
לא מבינים? אז החלק הבא הוא בשבילכם.

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

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

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

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

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

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

המחלקה

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

[sourcecode language="java"]
public class Car {

}
[/sourcecode]

בואו נתעלם לרגע מהמילה public בשורה הראשונה. קטע הקוד הקצר הזה הגדיר למחשב מבנה חדש (מחלקה) בשם Car שיכול לשמש אותנו בכל דרך שנבחר לממש.
שימו לב שבתוך הסוגרים המסולסלים לא יופיע קוד לבקרת זרימה (משפטי if או לולאות) אלא הגדרות של תכונות (משתנים) ופעולות (פונקציות), אותם נגדיר מיד.
אחרי שהגדרנו את המחלקה (המבנה של העצם), נותר רק להגדיר עצם מהסוג של המחלקה ולהשתמש בו. שימו לב לדוגמא הבאה:

[sourcecode language="java"]
public class Car {

}

Car AndyCar = new Car();
Car ProfessorCar = new Car();
[/sourcecode]

בדוגמא הזאת הגדרנו מחלקה חדשה בשם Car (המחלקה ריקה ועדיין לא הגדרנו לה תכונות ופעולות) ולאחר מכן יצרנו שתי עצמים מהסוג של המחלקה שלנו בשם AndyCar ו ProfessorCar (שורות 5 ו 6).
ונחזור לתיכנות מונחה עצמים.
ישנם שלושה עקרונות בסיסיים לגבי מחלקות, בתיכנות מונחה עצמים:

עיקרון 1 – כימוס (Encapsulation)

הכימוס מאפשר לנו להגדיר האם תכונה או פעולה בתוך המחלקה שלנו יהיו ציבוריים (כלומר, יהיה ניתן לקרוא להם מחוץ למחלקה) או האם הם יהיו פרטיים (כלומר, ניתן יהיה לקרוא להם רק מתוך המחלקה עצמה).
יותר מזה, ניתן אפילו להגדיר האם המחלקה עצמה היא פרטית או ציבורית (ומכאן ההסבר למילה public בשורה 1 בקטע קוד הקודם). למה צריך את זה? נניח לדוגמא שהפעולה של "הגבר מהירות" כוללת בתוכה סידרה של פעולות נוספות כמו הפחתה גדולה יותר של כמות הדלק במכונית (כתוצאה מהמהירות הגבוהה יותר). מי שמשתמש בעצם (מחלקה) של הרכב בסה"כ רוצה להגביר את המהירות. הוא אינו מעוניין וגם לא צריך לדעת מה בדיוק קורה מאחורי הפעולה הזה ומכאן שאין צורך לחשוף לו את זה.

בואו ונגדיר שוב, הפעם בקוד, את המחלקה של המכונית עם התכונות והפעולות שתיארנו מקודם:

[sourcecode language="java"]
public class Car {

private String color;
private int speed;
private int gasInTank;

public void increaseSpeed()
{
this.speed++;
}

public void decreaseSpeed()
{
this.speed–;
}

public void addGas(int gasQuantity)
{
this.gasInTank = this.gasInTank + gasQuantity;
}

public int getGas()
{
return this.gasInTank;
}

public String getColor()
{
return this.color;
}

public Car (String carColor)
{
this.color = carColor;
this.gasInTank = 0;
this.speed = 0;
}
}
[/sourcecode]

אל תיבהלו, זה רק נראה גדול ומסובך אבל למען האמת, זה די פשוט. בואו נעבור על הקוד:
שורה 1: הגדרה של מבנה של מחלקה ציבורית חדשה בשם Car.
שורה 3: הגדרה של תכונה פרטית מטיפוס String בשם color, אשר תכיל את צבע המכונית.
שורה 4: הגדרה של תכונה פרטית מטיפוס int בשם speed, אשר תכיל את המהירות הנוכחית של המכונית.
שורה 5: הגדרה של תכונה פרטית מטיפוס int בשם gasInTank, שמכילה את כמות הדלק הנוכחית במכונית.

שימו לב כי שלושת התכונות הללו הינם פרטיות ולכן רק פונקציות (פעולות) אשר נמצאות בתוך המחלקה Car יכולות להשתמש בהן.

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

רגע! עצור! מה זה void!??
כאשר פונקציה מסויימת מחזירה void המשמעות היא שהפונקציה בעצם אינה מחזירה דבר ואין להכניס פקודת return בתוכה. בדוגמא של הפונקציה increaseSpeed הגברת מהירות המכונית היא
פעולה לוגית שאינה מצריכה החזרת ערך למי שקורא לה ולפיכך היא מוגדרת כ- void.

שורה 9: מכילה את בלוק הקוד של פעולת increaseSpeed בו אנחנו בעצם מגבירים את המהירות, כלומר מגדילים את התכונה speed.
שורה 12: הגדרה של פעולה ציבורית המחזירה void בשם decreaseSpeed, שאינה מקבלת פרמטרים ותפקידה הוא להוריד את מהירות המכונית.
שורה 14: מכילה את בלוק הקוד של פעולת decreaseSpeed בו אנחנו מנמיכים את המהירות, כלומר מקטינים את התכונה speed.
שורה 17: הגדרה של פעולה ציבורית המחזירה void בשם addGas, המקבלת פרמטר אחד מסוג int בשם gasQuantity המתאר כמה דלק עלינו להוסיף למכונית. הפעולה אחראית על הוספת דלק למיכל המכונית.
שורה 19: מכילה את בלוק הקוד של פעולת addGas בו אנחנו מוסיפים לתכונה gasInTank את כמות הדלק שקיבלנו בפרמטר gasQuantity.
שורה 22: הגדרה של פעולה ציבורית המחזירה int בשם getGas, שאינה מקבלת פרמטרים ותפקידה הוא להחזיר את כמות הדלק שיש כרגע במיכל.
שורה 24: מכילה את בלוק הקוד של פעולת getGas, והיא בעצם החזרת הערך שנמצא בתוך התכונה הפרטית gasInTank.
שורה 27: הגדרה של פעולה ציבורית המחזירה String בשם getColor, שאינה מקבלת פרמטרים ותפקידה הוא להחזיר לנו את צבע המכונית.
שורה 29: מכילה את בלוק הקוד של פעולת getColor והיא בעצם החזרת הערך שנמצא בתוך התכונה הפרטית color.

שימו לב שכדי להתייחס לתכונה ששייכת למחלקה, השתמשנו ב this (שורות 14,19,24,29).

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

שורה 32: הגדרה של בנאי המחלקה, אשר מקבל פרמטר אחד בשם carColor. שימו לב שאת הבנאי נהוג להגדיר לפני כל הפונקציות (פעולות) האחרות במחלקה, אך אנו הגדרנו אותו בשורה 32 כדי שיהיה יותר נוח להסביר.
שורות 34 עד 36: איפוס ראשוני של המשתנים במחלקת המכונית שלנו. שימו לב שבדוגמא שבשורה 32 ניתן לקבוע את צבע המכונית כאשר יוצרים את המחלקה, אבל המהירות ההתחלתית (speed) היא תמיד אפס.

קטע הקוד שכתבנו אינו שלם. ישנם נושאים רבים בהם אנחנו לא מטפלים, לדוגמא, מה קורה אם מישהו מוריד את מהירות הרכב בעזרת decreaseSpeed אל מתחת לאפס? או מעלה את המהירות מעבר למה שהרכב יכול? או מנסה להוסיף דלק מעבר למה שאפשר להכניס במיכל?
לשם כך יש להרחיב את הקוד בתוך הפונקציות בצורה שתטפל בכל במקרים הללו. לדוגמא, הנה שוב הפונקציה decreaseSpeed בצורה שלא תאפשר להוריד את המהירות מתחת לאפס:

[sourcecode language="java" l="12"]
public void decreaseSpeed()
{
if (this.speed >= 0)
this.speed–;
}[/sourcecode]

בצורה כזאת יש להרחיב גם את שאר חלקי הקוד ואולי אף להוסיף משתנים (תכונות) ופעולות (פונקציות) פרטיים ו/או ציבוריים נוספים.
גם כאן אני מזמין אתכם ליצור מחלקת Car משלכם ולחלוק איתנו באשכול השיעור בפורום הפיתוח בפורטל.

עקרונות נוספים בתיכנות מונחה עצמים

ישנם עוד שני עקרונות נוספים בתיכנות מונחה עצמים. הורשה (Inheritance) ורב-צורתיות (Polymorphism).
על עקרונות מעניינים אלו נדבר בהרחבה בשיעור הבא שלנו ובשיעור הנוכחי נתמקד במימוש מחלקות ושימוש בכימוס.

מימוש הקוד ב Eclipse

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

סדר בקוד – חבילות

לשם שמירה על הסדר, שפת Java מאלצת אותנו לסדר את הקוד שלנו בתוך חבילות (Packages). שמות החבילות מיוצגות בפועל בתוך סיפריות היררכיות על הדיסק הקשיח (ששמם זהה לשם החבילה) ובצורה כזאת יכול המחשב למצוא את הקוד שלנו ביתר קלות. וניתן דוגמא מתוך קטע הקוד שכתבנו והרצנו בשיעור הקודם.
הפעילו את Eclipse ושימו לב שבצד שמאל מופיע לכם "עץ החבילות" שאמור להיראות כך:

Eclipse Package Explorer

הסבר על מבנה העץ:
תחת סיפריית src (מלשון Source) מוגדרת חבילה בשם iAndroid.academy ובתוכנה יש קובץ בשם Test.java.
תחת החבילה iAndroid.academy ניתן להוסיף קבצים רבים אשר קשורים לאותה חבילה. לפיכך, חשוב מאד שגם לשם החבילה, כמו לכל דבר אחר, יהיה שם בעל משמעות ושכל הקבצים תחת אותה חבילה יהיו קשורים אליה.
שימו לב: הסטנדרט מגדיר כי שמות של חבילות יתחילו תמיד באות קטנה.

סדר בקוד – קבצים ומחלקות

כל מחלקה שנרצה להגדיר בתוכנית שלנו חייבת להיות בקובץ נפרד, כאשר שמו של הקובץ זהה לשם המחלקה, עם תוספת של java. בסופו.
בתמונת המסך למעלה ניתן לראות כי בתוך החבילה iAndroid.academy ישנו קובץ בשם Test.java שפתוח בצד ימין. בתוך הקובץ מוגדרת מחלקה בשם Test שהיא כאמור זהה לשם הקובץ בו היא שוכנת.
שימו לב: הסטנדרט מגדיר כי שמות של מחלקות (וקבצים של מחלקות) יתחילו תמיד באות גדולה.

הוספת חבילה חדשה

בואו ונוסיף חבילה חדשה לתוך הפרויקט שלנו.
ליחצו מקש ימני על src ובתפריט שנפתח ביחרו ב New ואז ב Package.
צרו מחלקה חדשה בשם iAndroid.cars (שימו לב, גם iAndroid וגם cars מתחילות באות קטנה, ע"פ הסטנדרט).

התוצאה צריכה להיראות כך:

Eclipse, New and Empty Package

הוספת מחלקה חדשה

ליחצו מקש ימני על iAndroid.cars וביחרו ב New ואז ב Class.
במסך שנפתח לכם, הזינו את שם המחלקה Car בתוך השדה Name וליחצו על Finish.

התוצאה צריכה להיראות כך:

Eclipse - New Class

מזל טוב! כרגע יצרתם מחלקה חדשה בשם Car (שימו לב לצד ימין) שנמצאת בתוך החבילה iAndroid.cars.
בשיעור הבא נכניס עוד מכוניות רבות לתוך החבילה iAndroid.cars.

קריאה לחבילה.

העתיקו והדביקו את קטע הקוד של המכונית שכתבנו למעלה לתוך הקובץ Car.java (שימו לב לא למחוק בטעות את השורה הראשונה package iAndroid.cars שמגדירה את החבילה אליה משתייכת המחלקה).
היכנסו לקובץ Test.java שנמצא תחת החבילה iAndroid.academy וכיתבו בשורה השניה את קטע הקוד הבא

import iAndroid.cars.*;

הקובץ כולו אמור להיראות כך:

[sourcecode language="java" l="12"]
package iAndroid.academy;

import iAndroid.cars.*;

public class Test {

/**
* @param args
*/
public static void main(String[] args) {

}
}
}[/sourcecode]

אז מה בעצם עשינו פה?
אמרנו למחשב בעצם ליבא (import) את כל המחלקות שנמצאות בחבילה iAndroid.cars.
כעת אנחנו יכולים ליצור אובייקט חדש מסוג Car ולהשתמש בו תחת Test.

שימו לב! בשפת ג'אווה עצמה ישנם מאות חבילות קוד מוכנות, אשר מגיעות יחד עם השפה. חבילות אלו מכילות אלפי מחלקות מוכנות בכל נושא שעולה על דעתכם (מתמטיקה, גראפיקה, רשתות ועוד) ובהם אנחנו יכולים להשתמש בקוד שלנו.
יתרה מכך, כדי לפתח תחת אנדרואיד אנו נשתמש בחבילות קוד שמגיעות יחד עם סביבת הפיתוח שהתקנו (ה- SDK, זוכרים?).

יצירת אובייקט חדש מסוג Car

בתוך הפונקציה המרכזית של התוכנית (main), רישמו את קטע הקוד הבא:

[sourcecode language="java"]
package iAndroid.academy;

import iAndroid.cars.*;

public class Test {

/**
* @param args
*/
public static void main(String[] args) {
Car myCar;
myCar = new Car("Black");

myCar.addGas(30);

System.out.println(myCar.getGas());
}
}
[/sourcecode]

הסבר על הקוד:
שורה 11: יצירת עצם חדש בשם myCar מסוג Car. שימו לב שהאובייקט לא אותחל ושעדיין לא ניתן להשתמש בו.
שורה 12: איתחול האובייקט וקריאה לבנאי שלו, תוך העברת הערך "Black" כפרמטר. לאחר שורה זאת בעצם ניתן להשתמש באובייקט.
שורה 14: קריאה לפעולה addGas לשם הוספת דלק לרכב.
שורה 16: הדפסת הערך החוזר מקריאה לפעולה getGas.

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

הריצו את התוכנית ע"י לחציה על Run בתפריט ואז שוב פעם Run. את התוצאה תוכלו לראות ב Console בתחתית המסך.


תרגיל

אנדיאחלה תרגיל פרופסור!
בין העונים נכונה יוגרל סוף שבוע רומנטי עם המורה ללשון (או עם הפרופסור).

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

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

להית'!

Share

האקדמיה לפיתוח לאנדרואיד

בואו ללמוד לפתח לאנדרואיד! אתם בטח זוכרים אותי בתור Andy מהבלוג הישן!

24 Comments

  1. קוסטה
    15/05/2010 בשעה 17:54

    תגיד לי למה במקום GETBIGGERNUMBER אתה לא משתמש ב MATH ? זה יותר קל ויותר קצר ככה תלמד אותם את כול ה MATץRANDOM וכול השאר ויהיה יותר קל
    ד"א אני שנה ראשונה במדעי המחשב שפת JAVA

    1. אנדי
      15/05/2010 בשעה 18:14

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

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

  2. קוסטה
    15/05/2010 בשעה 19:02

    שמע הורדתי את ה SDK ויש לי WIN 7 ופשוט אין לי מה לבחור ב גירסאת אנדרואיד

  3. קוסטה
    15/05/2010 בשעה 19:09

    עוד משהו לעיניינך ה -@ וה PARAM ARGS אפשר למחחוק את זה כי לא צריך את זה

    1. אנדי
      16/05/2010 בשעה 09:12

      קוסטה, יש לי 2 משימות בשבילך, בוא נראה אם תוכל לבצע אותם:

      1. תסביר לקהילה שלנו מה זה בעצם /* */, איך ניתן להשתמש בו ולמה ה- @param args מיותר לדעתך.
      2. תפתור את התרגיל שהפרופסור שלנו נתן בסוף השיעור (אשמח אם את הפיתרון תכתוב בפורום, כי יותר נוח שם.

      מה אתה אומר?

  4. קוסטה
    16/05/2010 בשעה 09:54

    נדמה לי שהPARM ARGS מיותר כי זה פשוט מסממן לך שסימנת את האופציה הראשונה שבמקום לרשום לך את ה STTC VOID MAIN זה עושה את זה אוטומטית
    ובקשר לכוכבית אין לי מושג בכול זאת אני לומד בסיס
    ונדמה לי שזה יגיע עד 0

  5. ZooZ
    16/05/2010 בשעה 17:43

    שאלה שנתקלתי בה בפתרון התרגיל: איך אני יכול שהאובייקט יודיע למי שקורא לו שהמתודה שנקראה נכשלה?
    בתכלס, כשאני מממש drive אני צריך לממש גם מתודה של הפחתת דלק. שם אני צריך להפחית רק בתנאי שאני לא יורד מתחת לאפס. ההפחתה האחרונה(שקוראת בקריאה האחרונה ל drive) יכולה אומנם להיות בדיוק בכמות דלק שנשארה במיכל אבל גם יכולה להיות על כמות גדולה ממנו. לדוגמה נשאר 20 דלק במיכל אבל פעולת ה drive רוצה 40. אני רוצה שה drive ייכשל כדי שהתכנית הראשית תדע שהפעולה הזו לא הושלמה. אני צריך להפוך את drive לטיפוס int או שגם מתודה שהיא void יכולה להחזיר ערך הצלחת ריצה?

    1. אנדי
      16/05/2010 בשעה 18:40

      ZooZ, תודה רבה לך על שאלה מצויינת!

      אני מציע לך להפוך את drive ל- boolean (כלומר שהפונקציה תחזיר truefalse) ובכל פעם שהמכונית הצליחה לנסוע, היא תחזיר true ובכל פעם שלא הצליחה (לדוגמא, כי אין דלק), היא תחזיר false.

      מה דעתך?

  6. אורי
    17/05/2010 בשעה 03:18

    היי אחלה מדריכים אבל מתי בערך יבואו המדריכים המעניינים?
    לי אישית לא חודש כלום(כבר שנתיים בJAVA)
    מחכה בקוצר רוח.
    ולגבי מה שקוסטה אמר זה דיי מיותר ה JAVADOC פה כל אחד בונה לעצמו ולא מתכוון לפרסם קבצי JAR לאנשים אחרים, אם הוא כן מתכוון לעשות את זה אז רצוי מאוד שיהיה JAVADOC.

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

    1. אנדי
      17/05/2010 בשעה 08:33

      עוד שיעור אחד על תיכנות מונחה עצמים ולאחריו נעבור לחלקים העסיסיים של תיכנות לאנדרואיד.
      תחזיקו מעמד! 🙂

  7. guest
    17/05/2010 בשעה 13:05

    רעיון נוסף: שהמתודה drive תחזיר int שיציין את כמות הדלק שנצרכה.
    זה יאפשר למי שקרא ל-drive לקבל יותר מידע מאשר רק true/false (נניח שרצינו לצרוך 40 יחידות דלק, והמתודה החזירה false, זה לא אומר לנו אם לא נסענו בכלל או שצרכנו 39 מתוך ה-40 שביקשנו).

    1. אנדי
      17/05/2010 בשעה 21:00

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

      אפשר לחילופין ש drive לא תחזיר כלום ובתוכנית המקורית פשוט לבדוק את כמות הדלק עם getGas במקום (לדוגמא, כתנאי הלולאה).
      זה פיתרון נוסף.

  8. אנדי
    17/05/2010 בשעה 21:27

    יש כבר הצעות לפיתרונות בפורום.
    אני ממליץ לכם להיכנס ולראות
    http://iandroid.co.il/phpBB3/topic3485.html

  9. שוהם
    02/11/2010 בשעה 16:38

    חברה,
    זה רק אני או שבהסבר על הבנאי של car מופיע במקום רק"black" כל הטקסט הבא:
    "Black"

  10. שוהם
    02/11/2010 בשעה 16:42

    טוב… לא צפיתי את זה… אני אנסה להסביר בעברית… 🙂
    במקום "black" מופיע: גרשיים , quot ,המילה בלאק באנגלית, quot , גרשיים

    (כשאני רושם את זה בתגובה כאן, כמו שזה מופיע, זה הופך גם לקוד HTML )

  11. E.M
    15/04/2011 בשעה 10:14

    באמת אחלה מדריך.. סחטיין על ההשקעה..
    יש לי שאלה?
    למה שאני מריץ את התכנית אני מקבל את השגיאה הבאה?
    #
    # A fatal error has been detected by the Java Runtime Environment:
    #
    # Internal Error (classFileParser.cpp:3375), pid=6044, tid=5400
    # Error: ShouldNotReachHere()
    #
    # JRE version: 6.0_24-b07
    # Java VM: Java HotSpot(TM) Client VM (19.1-b02 mixed mode windows-x86 )
    # An error report file with more information is saved as:
    # D:workspaceMy First Project2hs_err_pid6044.log
    #
    # If you would like to submit a bug report, please visit:
    # http://java.sun.com/webapps/bugreport/crash.jsp
    #

  12. אמיר
    18/04/2011 בשעה 21:18

    מה פירוש הסימן &gt ??

  13. ניב
    21/04/2011 בשעה 18:05

    כרגיל מדריך מצויין!
    תודה רבה 🙂

  14. eden1108
    08/05/2011 בשעה 17:47

    הי,אני לומד JAVA בסיסית כבר כמעט שנה(לא ברמה מתקדמת,זה בכל זאת בית ספר).
    בשורה 3 בקטע קוד הראשון-לא הבנתי מזה &gt ,בנוסף זה גם לא עבד לי בתוכנה,והנה הקוד המלא שרשמתי:
    int GetBiggerNumber(int x, int y)
    {
    if (x > y)
    return x;
    else
    return y;
    }

  15. eden1108
    08/05/2011 בשעה 17:48

    משום מה זה שינה לי את הGT ל< לא יודע למה

  16. eden1108
    08/05/2011 בשעה 18:25

    תגובתךpackage iAndroid.academy;

    import iAndroid.cars.*;

    public class Test {

    /**
    * @param args
    */
    public static void main(String[] args) {
    Car myCar;
    myCar = new Car("Black");

    myCar.addGas(30);

    System.out.println(myCar.getGas());
    }
    }
    סליחה על הפגזרת התגובות אבל מה אומר ה:&quot

  17. amits1995
    12/08/2011 בשעה 07:52

    הבנתי מה המטרה של שורת הקוד הזאת: (this.speed >= 0)
    שהמהירות לא תרד למתחת ל0 אבל מה זה >?
    לא היינו פשוט צריכים לעשות:
    if(this.speed>0)
    this.speed–;

  18. amits1995
    12/08/2011 בשעה 09:10

    אני לא מבין למה, הטעות בידי
    כשבאתר הכוונה ל < אני רואה & G T

  19. F0x32o
    07/10/2011 בשעה 20:18

    מכיוון והמדריך ערוך ב- XHTML
    בחלק מהדפדפנים אלו שפחות תומכים אתה מבחין בtag ה-HTML אשר משמש להדגשת טקסט &gt

    hxxp://www.talltech.com/student/imos2k/fp-projects/CWP-TOORR/link2/charactertags.htm

השאר תגובה