Рубрики
Без рубрики

Руководство по статическому ключевому слову в Java

Узнайте о статических полях Java, статических методах, статических блоках и статических внутренних классах.

Автор оригинала: baeldung.

1. введение

В этой статье мы подробно рассмотрим ключевое слово static языка Java. Мы узнаем, как мы можем применить ключевое слово static к переменным, методам, блокам, вложенным классам и какое это имеет значение.

2. Анатомия статического ключевого слова

В языке программирования Java ключевое слово static указывает, что конкретный член принадлежит самому типу, а не экземпляру этого типа .

Это означает, что создается только один экземпляр этого статического члена, который является общим для всех экземпляров класса.

Ключевое слово может быть применено к переменным, методам, блокам и вложенному классу.

3. Статические Поля (Или Переменные Класса)

В Java если поле объявлено статическим , то создается ровно одна копия этого поля и совместно используется всеми экземплярами этого класса . Не имеет значения, сколько раз мы инициализируем класс; всегда будет только одна копия поля static , принадлежащая ему. Значение этого поля static будет общим для всех объектов одного и того же класса.

С точки зрения памяти статические переменные попадают в определенный пул в памяти JVM, называемый Metaspace (до Java 8 этот пул назывался Permanent Generation или PermGen, который был полностью удален и заменен Metaspace).

3.1. Пример статического поля

Предположим, у нас есть класс Car с несколькими атрибутами (переменными экземпляра) . Всякий раз, когда новые объекты инициализируются из этого Car blueprint, каждый новый объект будет иметь свою отдельную копию этих переменных экземпляра.

Однако предположим, что мы ищем переменную, которая содержит количество инициализированных объектов Car и является общей для всех экземпляров, чтобы они могли получить к ней доступ и увеличить ее при инициализации.

Вот тут-то и появляются статические переменные:

public class Car {
    private String name;
    private String engine;
    
    public static int numberOfCars;
    
    public Car(String name, String engine) {
        this.name = name;
        this.engine = engine;
        numberOfCars++;
    }

    // getters and setters
}

Теперь для каждого объекта этого класса, который инициализируется, увеличивается одна и та же копия переменной количество автомобилей . Таким образом, в данном случае будут верны следующие утверждения:

@Test
public void whenNumberOfCarObjectsInitialized_thenStaticCounterIncreases() {
    new Car("Jaguar", "V8");
    new Car("Bugatti", "W16");
 
    assertEquals(2, Car.numberOfCars);
}

3.2. Веские причины для использования статических полей

  • Когда значение переменной не зависит от объектов
  • Когда значение должно быть общим для всех объектов

3.3. Ключевые моменты, которые необходимо запомнить

  • Поскольку переменные static принадлежат классу, к ним можно получить доступ напрямую, используя имя класса, и им не нужна ссылка на объект
  • статические переменные могут быть объявлены только на уровне класса
  • статические поля могут быть доступны без инициализации объекта
  • Хотя мы можем получить доступ к статическим полям , используя ссылку на объект (например, ford.numberOfCars++ ), мы должны воздержаться от его использования, так как в этом случае становится трудно определить, является ли это переменная экземпляра или переменная класса; вместо этого мы всегда должны ссылаться на статические переменные, используя имя класса (например, в этом случае Car.numberOfCars++ )

4. Статические Методы (Или Методы Класса)

Подобно static полям, static методы также принадлежат классу, а не объекту, и поэтому их можно вызывать без создания объекта класса, в котором они находятся. Они предназначены для использования без создания объектов класса.

4.1. Пример статического метода

статические методы обычно используются для выполнения операции, которая не зависит от создания экземпляра.

Если есть код, который должен быть общим для всех экземпляров этого класса, напишите этот код в статическом методе:

public static void setNumberOfCars(int numberOfCars) {
    Car.numberOfCars = numberOfCars;
}

статические методы также широко используются для создания служебных или вспомогательных классов, чтобы их можно было получить без создания нового объекта этих классов.

Просто взгляните на Collections или Math служебные классы из JDK, StringUtils из Apache или CollectionUtils из Spring framework и обратите внимание, что все методы являются статическими .

4.2. Веские причины для использования статических методов

  • Для доступа/манипулирования статическими переменными и другими статическими методами, которые не зависят от объектов
  • статические методы широко используются в служебных и вспомогательных классах

4.3. Ключевые моменты, которые следует запомнить

  • статические методы в Java разрешаются во время компиляции. Поскольку переопределение метода является частью полиморфизма среды выполнения, поэтому статические методы не могут быть переопределены
  • абстрактные методы не могут быть статичными
  • статические методы не могут использовать это или супер ключевые слова
  • Допустимы следующие комбинации методов экземпляра, класса и переменных:
    1. Методы экземпляра могут напрямую обращаться как к методам экземпляра, так и к переменным экземпляра
    2. Методы экземпляра также могут напрямую обращаться к статическим переменным и статическим методам
    3. статические методы могут получить доступ ко всем статическим переменным и другим статическим методам
    4. статические методы не могут напрямую обращаться к переменным экземпляра и методам экземпляра ; для этого им требуется некоторая ссылка на объект

5. Статический Блок

Блок static используется для инициализации переменных static . Хотя переменные static могут быть инициализированы непосредственно во время объявления, бывают ситуации, когда нам требуется выполнить многострочную обработку.

В таких случаях пригодятся статические блоки.

Если статический переменные требуют дополнительной логики с несколькими операторами при инициализации, а затем статический блок можно использовать.

5.1. Пример статического Блока

Предположим, мы хотим инициализировать объект списка с некоторыми заранее определенными значениями.

Это становится легко с статическими блоками:

public class StaticBlockDemo {
    public static List ranks = new LinkedList<>();

    static {
        ranks.add("Lieutenant");
        ranks.add("Captain");
        ranks.add("Major");
    }
    
    static {
        ranks.add("Colonel");
        ranks.add("General");
    }
}

В этом примере было бы невозможно инициализировать объект List со всеми начальными значениями вместе с объявлением; и именно поэтому мы использовали здесь блок static .

5.2. Веские причины для использования статических блоков

  • Если инициализация статических переменных требует некоторой дополнительной логики, кроме назначения
  • Если инициализация статических переменных подвержена ошибкам и требует обработки исключений

5.3. Ключевые моменты, которые необходимо запомнить

  • Класс может иметь несколько статических блоков
  • статические поля и статические блоки разрешаются и выполняются в том же порядке, в каком они присутствуют в классе

6. Статический класс

Язык программирования Java позволяет нам создавать класс внутри класса. Это обеспечивает убедительный способ группировки элементов, которые будут использоваться только в одном месте, это помогает сохранить наш код более организованным и читаемым.

Архитектура вложенного класса разделена на две части:

  • вложенные классы, объявленные статическими , называются статическими вложенными классами , тогда как,
  • вложенные классы, которые не являются статическими , называются внутренними классами

Основное различие между этими двумя классами заключается в том, что внутренние классы имеют доступ ко всем членам заключающего класса (включая private), в то время как статические вложенные классы имеют доступ только к статическим членам внешнего класса.

На самом деле, статические вложенные классы вели себя точно так же, как и любой другой класс верхнего уровня, но были заключены в единственный класс, который будет иметь к нему доступ, чтобы обеспечить лучшее удобство упаковки.

6.1. Пример статического класса

Наиболее широко используемый подход к созданию одноэлементных объектов-это статический вложенный класс, он не требует никакой синхронизации и прост в освоении и реализации:

public class Singleton  {    
    private Singleton() {}
    
    private static class SingletonHolder {    
        public static final Singleton instance = new Singleton();
    }    

    public static Singleton getInstance() {    
        return SingletonHolder.instance;    
    }    
}

6.2. Веские причины для использования статического внутреннего класса

  • Группировка классов, которые будут использоваться только в одном месте, увеличивает инкапсуляцию
  • Код приближается к месту, которое будет только одним для его использования; это повышает читабельность и делает код более удобным для обслуживания
  • Если вложенный класс не требует какого-либо доступа к его заключающим членам экземпляра класса, то лучше объявить его как static , потому что таким образом он не будет связан с внешним классом и, следовательно, будет более оптимальным, поскольку им не потребуется память кучи или стека

6.3. Ключевые моменты, которые следует запомнить

  • статические вложенные классы не имеют доступа ни к каким членам экземпляра заключающего внешнего класса ; он может получить доступ к ним только через ссылку на объект
  • статические вложенные классы могут обращаться ко всем статическим членам заключающего класса, включая частные
  • Спецификация программирования Java не позволяет нам объявлять класс верхнего уровня как static ; только классы внутри классов (вложенные классы) могут быть сделаны как static

7. Заключение

В этой статье мы видели ключевое слово static в действии. Мы также читаем о причинах и преимуществах использования статических полей, статических методов, статических блоков и статических внутренних классов.

Как всегда, мы можем найти полный код на GitHub .