ראשי
פרק 1
פרק 2
פרק 3
פרק 4
פרק 5
פרק 6
פרק 7
פרק 8

פרק 3 - מחלקות ועצמים


תוכן הפרק:

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



תיאור מחלקה ומושג העצם

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

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

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


למעלה

הגדרת מחלקות ויצירת עצמים

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

הסבר:
הצהרנו על מחלקה בשם person שלה 3 משתנים. שני משתנים מסוג int, לייצוג של מספר ת"ז ותאריך לידה, ומשתנה מסוג String, לייצוג שם האדם. בנוסף הצהרנו גם על פונקציה בשם insert שמקבלת 3 משתנים בהתאם ומשימה אותם לתוך ערכי הפונקציה.
הערות:
אפשר לאתחל (לתת ערך התחלתי) כל משתנה בזמן ההגדרה. הערך ינתן למשתנה עם יצירת העצם. ערכים שלא יאותחלו יקבלו את הערך 0 בתור ברירת מחדל (false למשתנים בוליאניים ו null למצביעים).
לכל פונקציה תנתן אפשרות להגבלת הגישה אליה ע"י נתינת הערכים public, protected ו private, כשברירת המחדל היא package.


למעלה

יצירת עצמים

יצירת עצמים בג'אווה כוללת שני שלבים:
1. נתינת שם לעצם ספציפי עפ"י המחלקה - הגדרת reference.
לדוגמא:
;person p1, p2
;car volvo

כלומר, הגדרנו מופעים p1,p2 של המחלקה person ומופע volvo של המחלקה car.
2. הקצאת העצם - הקצאת העצם תעשה ע"י הוראת new.
;( ) <שם המחלקה > new = <שם המופע>
לדוגמא:
;( )p1 = new person
;( )p2 = new person
;( )volvo = new car
אפשר להקצות גם מערך שלם. לדוגמא:
;[ ]person p
למערך של עצמים כזה לא תספיק הוראת new אחת (כדוגמת ++C):
;[p = new person[2
מכיוון שעדיין לא הקצנו לכל איבר במערך מצביע עליו, אלא רק הקצנו מקומות למצביעים. לכן, להשלמת הפעולה, נצטרך להוסיף עוד הקצאות:
;( )p[0] = new person
;( )p[1] = new person

אפשר לשלב את שני השלבים לשלב אחד:
;( )person p = new person
;[person q [ ] = new person[2


למעלה

בקרת גישה

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

  • private - הגישה מותרת רק לפונקציות של המחלקה עצמה.
  • protected - הגישה מותרת גם לפונקציות היורשות את המחלקה.
  • package - הגישה מותרת לכל הפונקציות ששיכות למחלקות שבאותה חבילה כמו המחלקה שלנו.
  • public - הגישה מותרת לכל פונקציה שהיא.

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

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


למעלה

אתחול עצמים - constructor

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

קריאה ל constructor

ניצור עצם מסוג car במחלקה הראשית (נקרא לה world) וניתן לו פרמטרים מיידית לאתחול.
קריאה ל constructor

הצהרנו על מערך של עצמים מסוג car ואתחלנו בעזרת ה constructor את העצמים. כעת יש שני עצמים בתוכנית מסוג car עם הערכים המתאימים שאתחלנו.

העמסת ה constructor

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

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

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

constructor מחדל

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

constructor העתקה

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

המצביע this

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

חסכנו כתיבת קוד, ע"י קריאה של קונסטרקטור אחד למשנהו.



למעלה

פונקצית סיום - destructor

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

השימוש העיקרי של הפונקציה יהיה לשחרר משאבים, כגון קבצים, וכן לאפשר לעצם שמסיים את חייו לדווח על כך.
אם רוצים לקבוע במדויק את זמן השחרור של המשאב (השחרור מתבצע ע"י המנגנון האוטומטי וא"א לדעת מתי ואם זה יתבצע), אפשר לקרוא לפונקצית ( )System.runFinalization, שתורה למכונת הג'אווה לבצע את כל פונקציות ה finalize שמטפלות בעצמים שאינם בשימוש בתוכנית, או, לחילופין, לקרוא לפונקצית (System.runFinalizersOnExit(true שתורה למכונת הג'אווה לקרוא לכל פונקציות הסיום עם תום התוכנית. אפשרות זו מומלצת פחות, מכיוון שהיא איננה בטוחה.

למעלה

חברי מחלקות סטטיים

משתנה סטטי

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

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

פונקציות סטטיות

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

למעלה