Статический импорт в Java (import static) - Вопросы
Всего: 5 вопросов
1. Что такое статический импорт (import static) в Java и что с его помощью можно импортировать?
Что такое статический импорт (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 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) внутри класса не компилируется?
Почему после 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, а когда лучше от него отказаться?
Когда стоит использовать статический импорт в 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 советует применять статический импорт умеренно - только когда иначе пришлось бы многократно повторять имя класса - и импортировать константы, а не реализовывать ради них «интерфейс констант».