JavaRush /בלוג Java /Random-HE /10 הערות על השינוי הסטטי ב-Java

10 הערות על השינוי הסטטי ב-Java

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

שדות סטטיים

כאשר אנו מציינים משתנה ברמת המחלקה, אנו מציינים שהערך שייך למחלקה. אם לא תעשה זאת, הערך של המשתנה יהיה קשור לאובייקט שנוצר באמצעות מחלקה זו. מה זה אומר? 10 הערות על השינוי הסטטי ב-Java - 2והעובדה היא שאם המשתנה אינו סטטי, אז לכל אובייקט חדש במחלקה הזו יהיה ערך משלו של המשתנה הזה, על ידי שינוי זה נשנה אותו אך ורק באובייקט אחד: למשל, יש לנו מחלקה Car עם non -משתנה סטטי:
public class Car {
  int km;
}
ואז בגדול:
Car orangeCar = new Car();
orangeCar.km = 100;

Car blueCar = new Car();
blueCar.km = 85;

System.out.println("Orange car - " + orangeCar.km);
System.out.println("Blue car - " + blueCar.km);
הפלט שאנו מקבלים הוא:

Orange car - 100
Blue car - 85
כפי שאתה יכול לראות, לכל אובייקט יש משתנה משלו, ששינויו מתרחש רק עבור אובייקט זה. ובכן, אם יש לנו משתנה סטטי, אז הערך הגלובלי הזה זהה לכולם: עכשיו יש לנו מכונית עם משתנה סטטי:
public class Car {
  static int km;
}
ואז אותו קוד ב-main ייצא לקונסולה:

Orange car - 85
Blue car - 85
הרי יש לנו משתנה אחד לכולנו, ובכל פעם אנחנו משנים אותו. משתנים סטטיים נגישים בדרך כלל לא על ידי הפניה לאובייקט - orangeCar.km, אלא על ידי שם המחלקה - Car.km

בלוק סטטי

ישנם שני בלוקי אתחול - רגיל וסטטי. הבלוק נועד לאתחל משתנים פנימיים. אם הבלוק תקין, אז המשתנים הפנימיים של האובייקט מאותחלים איתו, אבל אם הוא סטטי, אז משתנים סטטיים (כלומר משתני מחלקה) מוקצים להם. דוגמה למחלקה עם בלוק אתחול סטטי:
public class Car {
  static int km;

  static {
     km = 150;
  }
}

שיטה סטטית

שיטות סטטיות שונות משיטות רגילות בכך שהן קשורות גם למחלקה ולא לאובייקט. תכונה חשובה של שיטה סטטית היא שהיא יכולה לגשת רק למשתנים/שיטות סטטיות. כדוגמה, בואו נסתכל על מחלקה שתהיה מעין מונה שעוקב אחר קריאות למתודה:
public class Counter {
  static int count;

  public static void invokeCounter() {
     count++;
     System.out.println("Current counter value - " + count);
  }
}
בואו נקרא לזה בגדול:
Counter.invokeCounter();
Counter.invokeCounter();
Counter.invokeCounter();
ואנו מקבלים את הפלט לקונסולה:

Текущее meaning счётчика - 1
Текущее meaning счётчика - 2
Текущее meaning счётчика - 3

מחלקה סטטית בג'אווה

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

  public static class Car {
     public int km;
  }
}
יצירת מופע של מחלקה זו והגדרת הערך של המשתנה הפנימי:
Vehicle.Car car = new Vehicle.Car();
car.km = 90;
כדי להשתמש בשיטות סטטיות/משתנים/מחלקה, אנחנו לא צריכים ליצור אובייקט של אותה מחלקה. כמובן, יש לקחת בחשבון משנה גישה. לדוגמה, שדות privateנגישים רק בתוך המחלקה שבה הם מוצהרים. שדות protectedזמינים לכל הכיתות בתוך חבילה ( חבילה ), כמו גם לכל כיתות צאצאים מחוץ לחבילה. לפרטים נוספים, עיין במאמר " פרטי לעומת מוגן לעומת ציבורי ". נניח שיש שיטה סטטית increment()במחלקה Counterשתפקידה להגדיל את המונה count. כדי לקרוא לשיטה זו, אתה יכול להשתמש בהזמנה של הטופס Counter.increment(). אין צורך להפעיל מחלקה Counterכדי לגשת לשדה או שיטה סטטית. זהו ההבדל המהותי בין אובייקטים סטטיים ובלתי סטטיים (חברי כיתה). הרשו לי להזכיר לכם שוב שחברי מחלקה סטטית שייכים ישירות למחלקה, לא למופע שלה. כלומר, הערך של משתנה סטטי countיהיה זהה עבור כל האובייקטים מסוג Counter. בהמשך מאמר זה, נסקור את ההיבטים הבסיסיים של השימוש בשינוי הסטטי ב-Java, כמו גם כמה תכונות שיעזרו לך להבין מושגי תכנות מרכזיים.

מה שכל מתכנת צריך לדעת על ה-Static Modifier בג'אווה

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

    public class Counter{
    private int count;
    public static void main(String args[]){
       System.out.println(count); //compile time error
    }}

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

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

  3. Статические методы имеют преимущество в применении, т.к. отсутствует необходимость каждый раз создавать новый an object для доступа к таким методам. Статический метод можно вызвать, используя тип класса, в котором эти методы описаны. Именно поэтому, подобные методы How нельзя лучше подходят в качестве методов-фабрик (factory), и методов-утorт (utility). Класс java.lang.Math — замечательный пример, в котором почти все методы статичны, по этой же причине классы-утorты в Java финализированы (final).

  4. Другим важным моментом является то, что вы НЕ можете переопределять (Override) статические методы. Если вы объявите такой же метод в классе-наследнике (subclass), т.е. метод с таким же именем и сигнатурой, вы лишь «спрячете» метод суперкласса (superclass) instead of переопределения. Это явление известно How сокрытие методов (hiding methods). Это означает, что при обращении к статическому методу, который объявлен How в родительском, так и в дочернем классе, во время компиляции всегда будет вызван метод исходя из типа переменной. В отличие от переопределения, такие методы не будут выполнены во время работы программы. Рассмотрим пример:

    class Vehicle{
         public static void  kmToMiles(int km){
              System.out.println("Inside parent class/static method");
         } }
    
    class Car extends Vehicle{
         public static void  kmToMiles(int km){
              System.out.println("Inside child class/static method ");
         } }
    
    public class Demo{
       public static void main(String args[]){
          Vehicle v = new Car();
           v.kmToMiles(10);
      }}

    Вывод в консоль:

    Внутри родительского класса/статического метода

    Код наглядно демонстрирует: несмотря на то, что an object имеет тип Car, вызван статический метод из класса Vehicle, т.к. произошло обращение к методу во время компиляции. И заметьте, ошибки во время компиляции не возникло!

  5. Объявить статическим также можно и класс, за исключением классов верхнего уровня. Такие классы известны How «вложенные статические классы» (nested static class). Они бывают полезными для представления улучшенных связей. Яркий пример вложенного статического класса — HashMap.Entry, который предоставляет структуру данных внутри HashMap. Стоит заметить, также How и любой другой внутренний класс, вложенные классы находятся в отдельном файле .class. Таким образом, если вы объявor пять вложенных классов в вашем главном классе, у вас будет 6 файлов с расширением .class. Ещё одним примером использования является объявление собственного компаратора (Comparator), например компаратор по возрасту (AgeComparator) в классе сотрудники (Employee).

  6. Модификатор static также может быть объявлен в статичном блоке, более известным How «Статический блок инициализации» (Static initializer block), который будет выполнен во время загрузки класса. Если вы не объявите такой блок, то Java соберёт все статические поля в один список и выполнит его во время загрузки класса. Однако, статичный блок НЕ может пробросить перехваченные исключения, но может выбросить не перехваченные. В таком случае возникнет «Exception Initializer Error». На практике, любое исключение возникшее во время выполнения и инициализации статических полей, будет завёрнуто Java в эту ошибку. Это также самая частая причина ошибки «No Class Def Found Error», т.к. класс не находился в памяти во время обращения к нему.

  7. Полезно знать, что статические методы связываются во время компиляции, в отличие от связывания виртуальных or не статических методов, которые связываются во время исполнения на реальном an objectе. Следовательно, статические методы не могут быть переопределены в Java, т.к. полиморфизм во время выполнения не распространяется на них. Это важное ограничение, которое необходимо учитывать, объявляя метод статическим. В этом есть смысл, только тогда, когда нет возможности or необходимости переопределения такого метода классами-наследниками. Методы-фабрики и методы-утorты хорошие образцы применения модификатора static. Джошуа Блох выделил несколько преимуществ использования статичного метода-фабрики перед конструктором, в книге «Effective Java», которая является обязательной для прочтения каждым программистом данного языка.

  8. Важным свойством статического блока является инициализация. Статические поля or переменные инициализируются после загрузки класса в память. Порядок инициализации сверху вниз, в том же порядке, в Howом они описаны в исходном файле Java класса. Поскольку статические поля инициализируются на потокобезопасный манер, это свойство также используется для реализации паттерна Singleton. Если вы не используется список Enum How Singleton, по тем or иным причинам, то для вас есть хорошая альтернатива. Но в таком случае необходимо учесть, что это не «ленивая» инициализация. Это означает, что статическое поле будет проинициализировано ещё ДО того How кто-нибудь об этом «попросит». Если an object ресурсоёмкий or редко используется, то инициализация его в статическом блоке сыграет не в вашу пользу.

  9. Во время сериализации, также How и transient переменные, статические поля не сериализуются. Действительно, если сохранить любые данные в статическом поле, то после десериализации новый an object будет содержать его первичное (по-умолчанию) meaning, например, если статическим полем была переменная типа int, то её meaning после десериализации будет равно нулю, если типа float – 0.0, если типа Objectnull. Честно говоря, это один из наиболее часто задаваемых вопросов касательно сериализации на собеседованиях по Java. Не храните наиболее важные данные об an objectе в статическом поле!

  10. ולבסוף, בואו נדבר על static import. לשינוי זה יש הרבה מן המשותף לאופרטור הסטנדרטי import, אך בניגוד אליו, הוא מאפשר לך לייבא אחד או את כל החברים הסטטיים של מחלקה. כאשר מייבאים שיטות סטטיות, ניתן לגשת אליהן כאילו הן הוגדרו באותה מחלקה, באופן דומה כאשר מייבאים שדות, נוכל לגשת אליהן מבלי לציין את שם המחלקה. תכונה זו הוצגה בגרסה 1.5 של Java, וכאשר נעשה בה שימוש נכון, משפרת את קריאות הקוד. בנייה זו נמצאת לרוב בבדיקות JUnit , כי כמעט כל מפתחי הבדיקות משתמשים static importבשיטות אסטרט, למשל, assertEquals()ובשכפולים העמוסים שלהם. אם שום דבר לא ברור, מוזמן למידע נוסף .

זה הכל. כל מתכנת חייב לדעת את כל הנקודות לעיל על השינוי הסטטי ב-Java . מאמר זה כיסה מידע בסיסי על משתנים סטטיים, שדות, שיטות, בלוקי אתחול וייבוא. כולל כמה מאפיינים חשובים, שהידע בהם הוא קריטי בעת כתיבה והבנה של תוכניות ב-Java. אני מקווה שכל מפתח ישכלל את כישוריו בשימוש במושגים סטטיים כי... זה מאוד חשוב לתכנות רציני".
הערות
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION