לא מצליח להבין את הצורך ב- static initilization

לא מצליח להבין את הצורך ב- static initilization

?שלום,
בעיקרון מתעסק בגאווה אבל מניח שזה תקף לכל שפת תכנות מונחית עצמים.
מנסה להבין מה זה בלוק סטטי שנועד לטיפול במשתני מחלקה. באתר של אורקל קראתי שזה מיועד כדי שאפשר יהיה ל״הכניס״ לוגיקה בהשמות שלהם בדיוק כמו שעושים עבור משתני מופע בבנאים למיניהם. אז למה אי אפשר להכניס לבנאים האלה לוגיקה גם עבור משתני המחלקה, לא ידוע לי על איסור להשמות של משתני מחלקה בבנאים. אשמח אם מישהו יוכל לשפוך לי קצת אור על הנושא. בנוסף שאלה קצרצרה בגלל שאני כרגע לא זמין מול מחשב רציתי לשאול אם אפשר לעשות השמה למאפיין (attribute) מופע כבר בשורת ההגדרה. לדוגמא:
Class dog
}
ClassB b=new ClassB();
 

BravoMan

Active member
זה מאוד פשוט:

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

קודם כל תןדה על המענה. מתנצל שלקח לי כמעט ארבעה ימים להגיב אבל הייתי ב-Funjoya ומתי שלא ניסיתי להיכנס לפורום כדי לקרוא לא הייתי מספיק פיקח (;
שנית, לא הבנתי שני דברים:
1.לא הבנתי מה הרעיון מאחורי ומה הכוונה בכלל באובייקט סרק? אני זוכר שראיתי בעבר שיש אפשרות להכניס פעולת new לאובייקט סטטי גם בבנאי (אלא אם כן הוא final)
2.האם כדי שקטע הקוד בבלוק הסטטי שדימית אותו לסוג של בנאי ירוץ, צריך (לא בטוח שבכלל אפשר) להריץ פקודת new באותו מקום שהכרזתי על משתנה סטטי של מחלקה?
תודה על ההסבר המושקע ובאמת סליחה שיצא כאילו התעלמתי. לא ממש הייתי במצב לענות );
 

BravoMan

Active member
הכל טוב, לא צריך להתנצל


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


1. האם הדברים שאמרת מתאימים בעיקר למצב שמאפייני המחלקה הם מטיפוסים מורכבים ולא מטיפוסים פרימיטיביים? (במידה ולמאפיינים הפרימיטיביים אין לוגיקה שצריכה להיבדק)?
2. האם אפשר (גם אם לא רצוי) עבור מאפיין מחלקה שהינו סטטי (ולא פרימיטיבי) לרשום new כבר בשורת ההגדרה של המחלקה (דוגמא למטה)? הבנתי ממך בתחילת השרשור שלמאפיין של אובייקט ולא מחלקה כן אפשר
דוגמא:
קוד:
public class Dog
{
static SomeNotPrimitiveClass a=new SomeNotPrimitiveClass();
}

3.האם כל מה שכתוב בבלוק הסטטי מתבצע עם עליית ה- JVM? במידה וכן, כאשר נבנה אובייקט עם רפרנס סטטי איפה נשמר האובייקט מבחינת מבנה הזיכרון ואיפה נשמר הרפרנס?
4. ראיתי ציטוט באיזשהו אתר שאומר: "This code inside static block is executed only once: the first time you make an object of that class or the first time you access a static member of that class (even if you never make an object of that class)."
מהטקסט הזה משתמע שיש תרחיש שקטע הקוד הזה יתבצע אחרי אחרי יצירת אובייקט מהמחלקה. האם זאת טעות?
 

BravoMan

Active member
אוקיי, בוא נראה:

1. זה לא משנה מה הטיפוס.
מישהו צריך לאתחל אותו. לאיברי מחלקה ואובייקט ב-Java יש אתחול ברירת מחדל, למשל int יאותחל אוטומטית ל-0 גם אם לא תכתוב אתחול מפורש.
&nbsp
כל משתנה מסוג reference יאותחל ל-null אם לא תשים שם new.
&nbsp
2. זה לא משנה.
אתה יכול להתייחס להצבה הזו כחלק מבלוק static. הקומפיילר ידחוף את האתחול הזה לאותו מקום בדיוק.
&nbsp
בלוק static ב-Java הוא מה שנקרא "syntactic sugar" ונועד לאפשר לך לרשום אתחולים מורכבים לאיברים סטטיים בצורה מסודרת ויפה יותר.
&nbsp
מבחינת התוצר הסופי, זה לא משנה אם אתה מאתחל היכן שאתה מגדיר, או בתוך בלוק סטטי נפרד.
&nbsp
3 ו-4 שאלה טובה.
אני לא בטוח. לדעתי, מתי בדיוק הקוד מתבצע תלוי במימוש ה-VM הספציפי.
רק לידיעה - יש יותר מ-VM אחד שמריץ Java.
&nbsp
לפי מה שראיתי, OpenJDK מריץ את הבלוק הסטטי רק כשהוא ממש צריך את המחלקה הרלוונטית, כלומר, לפני השימוש הראשון במחלקה בקוד.
רק שסתם הכרזת משתנה מהטיפוס הזה לא נחשב לשימוש.
גישה לאיבר סטטי לאומת זאת, כן.
&nbsp
למיטב ידיעתי, אובייקטים סטטיים נשמרים על ה-Heap כמו כל האובייקטים.
&nbsp
שים לב שלשפת Java יש תקן.
אם אתה ממש רוצה להתעמק בפרטים הטכניים של איך JVM אמור לעבוד, ממליץ להתחיל כאן:
https://docs.oracle.com/javase/specs
&nbsp
בהצלחה!
 
היי..התייחסות לסעיפים בגוף ההודעה

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

BravoMan

Active member
כמה דברים:

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

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

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

הבנאי הזה מכיל את כל האתחולים של האיברים הסטטיים, גם כאלה שנכתבו כך:
static Car myCar = new Car();

וגם כאלה שנכתבו כך:
קוד:
static Car myCar;

static {
    if (user.Rich)
       myCar = new Car("Ferari");
    else
       myCar = new Car("Kia");
}

3. לגבי עבודה עם זיכרון:
אני מכיר פחות את ה-JVM השולחני, ואני חושב שהוא עובד עם Stack.
אני מכיר יותר את Dalvik, שהוא JVM של Android, והוא מבוסס על registers (ווירטואליים, לא הפיזיים של המעבד).

לפי כך, לשפת Java יש 2 אפשרויות אחסון ב-RAM:
מחסנית \ רגיסטרים (תלוי במימוש VM) לדברים איתם עובדים במיידי כגון משתנים מקומיים של פונקציות, רפרנסים שנכנסים לשימוש, וערכים פרימיטיביים שעושים איתם חישובים.

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

4. לא כל שפות מונחות עצמים עובדות אותו דבר "מתחת למכסה"!
++C למשל, עובד ללא VM, אלא מקומפלת לקוד מכונה native.

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

זה משהו ש-++C מאפשר, אבל Java לא.

למעשה, כל הניהול של הזיכרון ב-++C שונה מאוד, וכך גם רפרנס לאובייקט יכול להישמר על ה-heap בתנאים מסוימים (בשביל זה יש מצביעים).
דוגמה:
קוד:
void func() {
    Car myCar; //object created statically on stack every time function called, automatically destroyed when function ends

    Car *componyCar = new Car(); //object created dynamically on heap, and remains until delete is used
}
 
תודה הבנתי הרבה יותר ממה שידעתי לפני כמה ימים :)

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