> For the complete documentation index, see [llms.txt](https://opu.gitbook.io/oop/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://opu.gitbook.io/oop/2019-2020-archive/arkhiv-1/arkhiv/lekcii/blok-lekcii-5-1/untitled.md).

# Статические поля и методы

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

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

Такой эффект достигается путем использования ключевого слова `static`, делающего элемент класса **статическим**. Поля или методы, которые объявлены как `static`, не привязаны к определенному экземпляру этого класса. Поэтому даже если в программе еще не создавался ни один объект класса, вы можете вызывать статический метод или получить доступ к статическим полям. С обычным объектом вам необходимо сначала создать его и использовать для вызова метода или доступа к полям, так как нестатические данные должны точно знать объект, с которым работают.

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

### Понятие статического поля

Чтобы сделать данные или метод статическими, просто поместите ключевое слово `static` перед их определением. Например, следующий код создает статическое поле класса и инициализирует его:

{% code title="StaticTest.java" %}

```java
class StaticTest {
    static int val = 924;
}
```

{% endcode %}

Теперь, даже при создании двух объектов `StaticTest`, для элемента `StaticTest.val` выделяется единственный блок памяти. Оба объекта совместно используют одно значение `val`. Пример:

```java
StaticTest st1 = new StaticTest();
StaticTest st2 = new StaticTest();
```

В данном примере как `st1.val`, так и `st2.val` имеют одинаковые значения, равные 924, потому что они ссылаются на один блок памяти.

Существует два способа обратиться к статической переменной. Как было видно выше, на нее можно ссылаться по имени объекта, например `st2.val`. Также возможно обратиться к ней прямо через имя класса; для нестатических членов класса такая возможность отсутствует.

```java
StaticTest.val++;
```

После выполнения операции, значения `st1.val` и `st2.val` будут равны 48.

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

Если для инициализации статических переменных требуется произвести вычисления, то для этой цели достаточно объявить **статический блок**, который будет выполняться только один раз при первой загрузке класса. Пример:

```java
class NetworkConnector {

    public static final int baud;
    private static final int bits_per_interval = 4;

    static {
        baud = 9600 / bits_per_interval;
    }

    // ...
}
```

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

### Понятие статического метода

Та же логика верна и для статических методов. Вы можете обратиться к такому методу или через объект, как это делается для всех методов, или в специальном синтаксисе **ИмяКласса.метод()**. Статические методы определяются по аналогии со статическими данными:

```java
class Incrementable {
    static void increment() {
        StaticTest.val++;
    }
}
```

Нетрудно заметить, что метод `increment()` класса `Incrementable` увеличивает значение статического поля `val`. Метод можно вызвать стандартно, через объект:

```java
Incrementable sf = new Incrementable();
sf.increment();
```

Или, поскольку метод increment() является статическим, можно вызвать его с прямым указанием класса:

```java
Incrementable.increment();
```

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

На статические методы налагаются следующие ограничения:

* они могут непосредственно вызывать только другие статические методы;
* им непосредственно доступны только статические переменные;
* им недоступны ключевые слова **this** или **super**.

### Статический импорт

В языке Java имеется языковое средство, расширяющее возможности ключевого слова `import` и называемое **статическим импортом**. Оператор `import`, предваряемый ключевым словом `static`, можно применять для импорта статических членов класса или интерфейса. Благодаря статическому импорту появляется возможность ссылаться на статические члены непосредственно по именам, не используя имя класса. Это упрощает и сокращает синтаксис, требующийся для работы со статическими членами.

Рассмотрим пример без использования статического импорта. Представим себе, что мы вычисляем гипотенузу прямоугольного треугольника. Мы будем часто использовать методы `Math.pow()` и `Math.sqrt()`

```java
double side1 = 3.0;
double side2 = 4.0;
double hypot;

hypot = Math.sqrt(Math.pow(side1, 2) + Math.pow(si de2, 2));
```

Как мы видим, строка&#x20;

```java
hypot = Math.sqrt(Math.pow(side1, 2) + Math.pow(side2, 2));
```

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

```java
import static java.lang.Math.pow;
import static java.lang.Math.sqrt;

public class Main {
    public static void main(String[] args) {

        double side1 = 3.0;
        double side2 = 4.0;
        double hypot;

        hypot = sqrt(pow(side1, 2) + pow(side2, 2));
    }
}
```

После использования статического импорта нет нужды использовать имя класс `Math` для вызова статических методов `pow()` и `sqrt()`.

Если предполагается применять много статических методов или полей, определенных в классе, то можно импортировать класс `Math` полностью

```java
import static java.lang.Math.*;
```

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