Menu

static ב-Java: שדות ומתודות סטטיים

מה עושה מילת המפתח static ב-Java, איך שדות ומתודות סטטיים שייכים למחלקה ולא לאובייקטים, ומתי כדאי להשתמש בבלוקים סטטיים ובקבועים.

בדף הזה יש עורכים שאפשר להריץ - לערוך, להריץ ולראות את הפלט מיד.

שייכות למחלקה, לא לאובייקט

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

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

שדה static משותף

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

שימו לב שקוראים את המונה כ-User.count, דרך שם המחלקה, כי הערך לא שייך לאף User מסוים. כל name, לעומת זאת, חי בתוך האובייקט שלו. שנו את count דרך מופע כלשהו, וכל המופעים יראו את הערך החדש, כי יש רק אחד כזה.

מתודות static

גם מתודה static שייכת למחלקה, ולכן קוראים לה על המחלקה בלי אובייקט:

זה בדיוק הדפוס שמאחורי הספרייה הסטנדרטית: Math.max, Integer.parseInt, Arrays.sort ו-List.of הן כולן static, התנהגות עזר שלא צריכה אובייקט כדי לפעול. השתמשו במתודה static כשהעבודה תלויה רק בארגומנטים שלה, ולא במצב של אובייקט כלשהו.

המלכודת הגדולה: static לא רואה איברי מופע

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

class Account {
    int balance = 100;          // שדה מופע

    static int show() {
        return balance;         // שגיאת קומפילציה: השדה הלא סטטי 'balance'
    }                           // לא ניתן להפניה מהקשר סטטי
}

התיקון הוא להפוך את המתודה למתודת מופע (להסיר את static, כדי שיהיה לה this), או להעביר את האובייקט במפורש:

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

קבועים עם static final

משלבים static עם final ומקבלים קבוע: ערך משותף אחד שלעולם לא משתנה. לפי המוסכמה, השמות שלהם נכתבים ב-UPPER_SNAKE_CASE:

static final היא הדרך המקובלת לבטא "ערך קבוע ששייך לטיפוס", כמו Integer.MAX_VALUE או Math.PI בספרייה הסטנדרטית. static אומר שלא מבזבזים עותק לכל אובייקט; final אומר שאף אחד לא יכול לשייך אותו מחדש.

בלוקי אתחול static

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

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

מתי להשתמש ב-static

כלל אצבע מהיר:

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

הבא: Enums

קבוע static final מתאים לערך קבוע אחד, אבל כשיש קבוצה קטנה וקבועה של ערכים קשורים, כמו כיוונים, ימי השבוע או סטטוסים של הזמנה, ל-Java יש טיפוס ייעודי שבטוח ומבטא יותר מקבועים מפוזרים. זה ה-enum, וזה העמוד הבא.

שאלות נפוצות

מה המשמעות של static ב-Java?

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

מה ההבדל בין משתנה סטטי למשתנה מופע ב-Java?

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

למה המתודה main היא static ב-Java?

ה-JVM צריכה לקרוא ל-main לפני שקיים אובייקט כלשהו של המחלקה שלכם. מכיוון שמתודה static שייכת למחלקה ולא למופע, סביבת הריצה יכולה להפעיל את Main.main(args) ישירות בלי לבנות קודם Main. לכן החתימה היא תמיד public static void main(String[] args).

איור של שפות התכנות ב-Coddy

ללמוד תכנות עם Coddy

להתחיל