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

Обычно при создании класса вы описываете, как объекты этого класса ведут себя и как они выглядят. Объект появляется только после того, как он будет создан ключевым словом `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 объединяются в пакеты для того, чтобы избежать конфликтов пространств имен и непреднамеренного сокрытия прочих имен. Если статический член используется в программе один или два раза, то его лучше не импортировать. Статический импорт следует оставить на тот случай, если статический члены применяются многократно, в частности при выполнении математических вычислений.


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://opu.gitbook.io/oop/2019-2020-archive/arkhiv-1/arkhiv/lekcii/blok-lekcii-5-1/untitled.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
