Статический импорт в Java (import static) - Вопросы

Всего: 5 вопросов

1. 

Что такое статический импорт (import static) в Java и что с его помощью можно импортировать?

Статический импорт - это объявление import static, которое позволяет обращаться к статическим полям, статическим методам и вложенным статическим типам другого класса по простому имени, без префикса класса. Например, после import static java.lang.Math.PI; можно писать PI вместо Math.PI.

Статический импорт появился в Java 5. Импортировать можно только статические члены: поля и методы экземпляра (например, String.length()) через import static недоступны. Также нельзя импортировать недоступные (например, private) члены и члены классов из пакета по умолчанию.

2. 

Чем обычный import отличается от import static?

Обычный import импортирует типы (классы и интерфейсы): после import java.util.List; пишут List.of(1, 2). import static импортирует статические члены класса: после import static java.lang.Math.PI; пишут PI вместо Math.PI.

Форма со звёздочкой тоже различается: import java.util.*; - все типы пакета, import static java.lang.Math.*; - все статические члены класса. Пакет java.lang импортируется автоматически только на уровне типов, поэтому для cos(PI) без префикса всё равно нужен import static.

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

3. 

Чем одиночный статический импорт отличается от импорта со звёздочкой и что будет, если два импорта со звёздочкой приносят одинаковое имя?

Одиночный импорт (import static java.lang.Math.max;) подтягивает все статические члены с указанным именем, включая все перегрузки max; параметры метода в импорте не указываются. Импорт по требованию (import static java.lang.Math.*;) подтягивает все доступные статические члены класса.

Если import static java.lang.Integer.*; и import static java.lang.Long.*; оба приносят MAX_VALUE, ошибки нет, пока имя не используется. При обращении к MAX_VALUE компилятор сообщит reference to MAX_VALUE is ambiguous.

Решение - добавить одиночный импорт нужного члена (он имеет приоритет над импортом со звёздочкой) или написать полное имя Integer.MAX_VALUE. В рабочем коде обычно предпочитают поимённый импорт: сразу видно, откуда взято имя.

4. 

Почему после import static java.util.Arrays.toString; вызов toString(numbers) внутри класса не компилируется?

Имена, объявленные в самом классе или унаследованные им, затеняют статически импортированные. Каждый класс наследует от Object метод toString(), поэтому компилятор ищет toString(numbers) среди методов класса, находит Object.toString() без параметров и выдаёт ошибку method toString in class Object cannot be applied to given types.

Решение - вызвать метод с именем класса: Arrays.toString(numbers). То же касается equals и hashCode: статически импортировать, например, Objects.equals бесполезно - его затенит Object.equals.

5. 

Когда стоит использовать статический импорт в Java, а когда лучше от него отказаться?

Static import полезен, когда имя члена понятно само по себе и часто повторяется: математические выражения с Math (sqrt, pow, PI), assertions в тестах JUnit (assertEquals, assertTrue), коллекторы Stream API (groupingBy, counting), часто используемые константы и значения enum (MONDAY).

Лучше отказаться, если без имени класса непонятно, откуда взят член: of(1, 2) ничего не говорит читателю, а List.of(1, 2) - говорит. Импорт со звёздочкой из нескольких классов тоже усложняет чтение и грозит неоднозначностью. Oracle советует применять статический импорт умеренно - только когда иначе пришлось бы многократно повторять имя класса - и импортировать константы, а не реализовывать ради них «интерфейс констант».

Страница 1 из 1