
Array.time[] array = new time[5]; נוצר האובייקט של המערך, וכל תא כבר מכיל אובייקט time. אפשר להכניס לו ערכים מיד, בלי new נוסף.time הוא class, יוצרת רק תאים שהם רפרנסים. לכל תא צריך לבנות אובייקט בעזרת new.array[0] = new time();, ורק אז מכניסים ערכים לשדות שלו.int עובד בלי new לכל תא, כי int נולד מ-struct. כשעובדים עם מערכים בפרויקט, כדאי לבדוק אם איברי המערך הם value type או reference type.הטקסט המלא של הדקות הראשונות בהרצאה «מערך של אובייקטים - Objects Array» בקורס הווידאו של PracticU – כתוביות בעברית עם זמן התחלה לכל פסקה. כך תוכלו לקרוא ולחפש את הנושאים לפני שמתחילים ללמוד.
אחרי שראינו את ההבדלים בין value type ל-reference type אנחנו הולכים להסתכל על מה קורה כאשר אנחנו פותחים מערכים. אנחנו יכולים להגדיר מערך מסוג value type ואנחנו יכולים להגדיר מערך מסוג reference type ובזיכרון קורים דברים שונים לגמרי.
למה חשוב לנו לדעת את זה? מפני שכל הזמן קורה שאנחנו בפרויקטים בתכנות משתמשים במערכים. אז בדיוק כמו שהיה חשוב לנו להבין מה קורה בזיכרון כאשר יש לנו אובייקט אחד, כאשר הוא מ-value type או מ-reference type, מה קורה כאשר אנחנו שולחים אותו לפונקציה, איך הוא מתנהג בגלל הצורה שבה הוא בנוי בזיכרון.
אז ככה מאוד חשוב לנו להבין מה קורה כאשר אנחנו מתעסקים עם מערכים. אז בואו נמשיך מהפרויקט הקודם. יש לנו כאן את הקלאס שבנינו time, ואנחנו הולכים לשנות אותה בחזרה ל-struct.
זה אומר שכעת time הוא value type והוא מתנהג כ-value type, ואני רוצה לבנות מערך ממנו. יש לנו כאן את התוכנית הראשית, נשים אותו פה לידינו, פלושן אקספלורר אפשר לסגור, וכעת אנחנו רוצים לראות איך בעצם ניתן ליצור מערך מהדבר הזה.
את זה אני לא צריך, ואת זה אני לא צריך, נוריד מפה כל מיני דברים ישנים, ואני אשמור לאחר כך. אז איך אני בעצם מגדיר מערך?
אז אני יודע שאם אני רוצה להגדיר מערך של אינטג'ר, ואני פשוט כותב int, סוגריים מרובעים, array שווה new int, סוגריים מרובעים, נותן פה איזשהו גודל, עכשיו, אם אני רוצה לבנות מערך של טיים, נניח אני רוצה הרבה זמנים בתוכנית בבת אחת לנהל.
במקום int אני רושם time, בואו נעשה מערך בגודל 5. אז כאן יצרנו בעצם מערך. עכשיו, דבר ראשון, אנחנו צריכים להבין כזה דבר.
זה לא משנה אם time הוא value type או reference type. זאת אומרת, זה לא משנה מה בדיוק יצר את time, struct, class, enum וכולי.
מערך הוא תמיד reference type. המערך הוא תמיד קלאס. זה בעצם איזושהי מחלקה שיורשת מחלקת בסיס של כל המערכים שנקראת array. array זאת מחלקת הבסיס של כל המערכים, אנחנו רואים כאן שהיא קלאס.
אז כל מערך שאנחנו בונים, לא משנה מה יצר אותו, הוא רפרנס טייפ מפני שהוא נגזר מקלאס. כאשר אתם לוחצים נקודה על המערך, אתם רואים המון המון פונקציות.
מי כתב את כל הפונקציות האלה? הרי אנחנו לא כתבנו אותן. הגיעו ממחלקת הבסיס מRA. אוקיי, אז יש לנו עכשיו את המערך הזה ואנחנו רוצים לבוא ולהכניס ערכים למשתנים שלו.
אז יש לנו פה גישה כמובן לתא מסוים, בואו נניח תא מספר 0 ואנחנו יכולים ללכת ל-Hour ולהכניס לתוכו איזשהו ערך, בואו נניח 10. יש לנו שוב פעם גישה לתא הראשון, מינט, נניח 0.7, יש לנו עוד פעם גישה לתא הראשון,
Second 30. בואו נשתמש בקוד הזה בשביל להציג אותו ואנחנו רוצים להציג את ה-Hour, את ה-Minute ואת ה-Second. נריץ ונראה שהכל עובד כמו שצריך.
עכשיו שימו לב שאנחנו כעת ביצענו New עבור יצירת כל המערך. לא ביצענו New עבור יצירת האובייקט האחד והיחיד מסוג Time, מפני ש-Time כרגע מוגדר כ-Value Type.
זאת הסיבה שלא היינו צריכים ליצור new עבור time. בדיוק כמו שכשלמדנו על value type ו-reference type, יכלנו לבנות time, my time, וזה בעצם היה יוצר לנו את האובייקט.
לא היינו צריכים ללכת וליצור new. היינו יכולים לבצע שווה new time למרות שהוא value type, וזה לא היה משנה את התמונה בזיכרון, וזה לא היה משנה את העובדה שזה עדיין value type ולא reference type.
זאת אומרת גם בצורה כזאת יכלנו ליצור אובייקט ספציפי מהטיים הזה כמו שראינו בדוגמה בלי ליצור ניו.
אז בדיוק אותו הדבר אנחנו לא היינו צריכים ללכת כאן וליצור ניו מהטיים הראשון. הניו שאתם רואים כאן שייך לכל האובייקט של המערך עצמו. בואו נבין מבחינה סכמטית מה קרה כאן בזיכרון.
אז יש לנו כאן את הזיכרון שהולך להיות עבור מערך שמכיל value types. אז אנחנו מדברים על StructTime שיש לה Hour, Minute ו-Second ואנחנו עכשיו יוצרים time == array ויוצר לנו רק תא זיכרון שנקרא array והוא בעצם רפרנס לאובייקט שהוא המערך עצמו, לא לאובייקט time, מפני שאמרנו שכל מערך הוא רפרנס טייפ.
הדבר הבא, עשינו שווה NewTime בגודל 5. כאן בעצם הם יצרנו את האובייקט עצמו של המערך. מערך הוא אובייקט, רפרנס טאב, ונוצר לנו אובייקט.
וכמובן הכתובת שלו נכנסה לתוך הרי, בואו נראה מה קרה לנו. אנחנו רואים שכל המערך הזה זה בעצם אובייקט מאוד מאוד גדול.
אנחנו רואים אותו פה, כל הדבר הזה. יש לכל תא אינדקס 0, 1, 2, 3 ו-4, וכל טאבו הוא מסוג תאים. וזאת הנקודה הכי חשובה שאנחנו צריכים להבין. אנחנו יוצרים מערך מסוג value type, זאת אומרת הטיפוס נתונים שיצר את המערך הוא value type, לדוגמה במקרה הזה time הוא value type כי הוא נוצר מסטראקט, אזי כל תא במערך והאובייקט עצמו ככה ועובד
עם מערכים של value type. לכן האובייקט עצמו של כל המערך מכיל חמישה אובייקטים מסוג time, שכל אחד יש לו כמובן hour, minute ו-second.
כל המערך יש כתובת, האובייקט שהוא מערך יש לו כתובת והכתובת נכנסה ל-reference array שמסוגל להחזיק כתובת של מערך.
הדבר הבא שעשינו זה מיד יכלנו לגשת ל-hour, minute ו-second של תא מספר 0 מפני שבתא מספר 0 כבר קיים לנו אובייקט time אז הכנסנו 10, 0, 7, 30 והופה נכנסו מיידית לתא הראשון.
עכשיו אם אנחנו רוצים לראות מה קורה בנוגע ל-reference type של כל תא בעצם הוא reference type במערכים, זה סיפור אחר לגמרי. בואו נחזור בחזרה ונסתכל על מצב שבו אנחנו הולכים ל-struct ומשנים אותו ל-class.
אז כעת ה-time שלנו הוא מטיפוס שהוא נוצר על ידי class ולכן הוא reference type כמובן. כל מה שעשיתי זה שיניתי מ-struct ל-class ואני רוצה להריץ את התוכנית.
שימו לב מה יקרה עכשיו, תוכנית קורסת, איך זה יכול להיות שכעת התוכנית קרסה? אם אנחנו נריץ אותה בעזרת הפליי, שזה אומר F5 ותתבצע קריסה, אז אנחנו נראה בדיוק את הפקודה שגרמה לקריסה והסבר על מה בדיוק קרה.
ואנחנו הולכים לראות שהדיבאגר נכנס לפעולה והוא מצביע לנו בדיוק על השורה הראשונה שבה ניסינו לגעת בתא הראשון, ואנחנו רואים שיש לנו פה איזה בעיה שנקראת null reference אקספשן, מה זה null אנחנו נסביר בהמשך, אובג'קט רפרנס not set to an instance of an object.
זאת דרך אגב שגיאת הריצה הנפוצה ביותר שקיימת לפי דעתי בעולם פיתוח התוכנה באובג'קט אוריינטד אבל היא גם די פשוטה לפתרון בין הבעיות שהכי קל לפתור אותן.
ומה שהמערכת אומרת לנו פה בעצם זה שקיים לנו רפרנס אבל אבל לא קיים בתוך הרפרנס שום כתובת לאובייקט אמיתי. כלומר לא קיימת שום כתובת לאובייקט אמיתי בתוך הרפרנס. במילים אחרות הרפרנס שלנו לא מצביע על שום אובייקט.
אם הוא לא מצביע על שום אובייקט זה נחשב שיש בו את הכתובת 0 שזה בעצם במילים אחרות null. null או נול בגרמנית זה 0 או כלום ולכן null זה ביטוי בעולם האוג'קטוריונטי שאומר הכתובת 0.
אם רפרנס לא מצביע על כלום אפשר להגיד שיש בו נ"ל או אם יש בו נ"ל אפשר להגיד שהוא לא מצביע על כלום. אבל למה קיבלנו את השגיאה הזאת עכשיו כאשר כל מה שעשינו זה שינינו מסטראקט לקלאס?