--- title: Пакеты и импорты description: Объявление пакетов, импорты, псевдонимы и автоматически импортируемые пакеты tags: - kotlin - syntax --- ## Пакет Объявляется первой строкой файла: ```kotlin package com.example.app fun helper() { } class Service ``` Полное имя функции - `com.example.app.helper`. Отличие от Java: **структура каталогов не обязана совпадать с пакетом**, и имя файла не связано с содержимым. Компилятор не возражает. На практике соглашение соблюдают: иначе навигация по проекту ломается. Файл без `package` попадает в корневой пакет (default package). ## Содержимое файла В одном файле может быть сколько угодно объявлений верхнего уровня: ```kotlin package com.example const val VERSION = "1.0" fun parse(text: String): Int = text.toInt() class User(val name: String) class Admin(val name: String) private fun internalHelper() { } // видна только в этом файле ``` Никаких `public class` на файл - ограничения «один публичный класс на файл» в Kotlin нет. ## Импорты ```kotlin import com.example.app.Service // конкретный класс import com.example.app.helper // функция верхнего уровня import com.example.app.* // всё из пакета import com.example.app.User.Companion.create // член companion object ``` Импортировать можно не только типы, но и функции, свойства, enum-константы - всё, что объявлено на верхнем уровне или как статический член. ```kotlin import kotlin.math.PI import kotlin.math.sqrt fun main() { println(sqrt(PI)) // 1.7724538509055159 } ``` ## Псевдонимы - as Когда имена конфликтуют или слишком длинные: ```kotlin import com.example.data.User as DataUser import com.example.api.User as ApiUser fun convert(u: DataUser): ApiUser = ApiUser(u.name) ``` Псевдоним действует только в своём файле. Если нужно имя на весь модуль - это [typealias](../Базовые%20типы%20ООП/Typealias.md). ## Импортируются автоматически Эти пакеты доступны без `import`: | Пакет | Что содержит | |---|---| | `kotlin.*` | `Int`, `String`, `Any`, базовые функции | | `kotlin.annotation.*` | аннотации | | `kotlin.collections.*` | `List`, `Map`, `listOf`, операции | | `kotlin.comparisons.*` | `compareBy`, `maxOf` | | `kotlin.io.*` | `println`, `readln` | | `kotlin.ranges.*` | диапазоны, `step`, `downTo` | | `kotlin.sequences.*` | `Sequence`, `sequenceOf` | | `kotlin.text.*` | операции со строками | | `java.lang.*` | только на JVM | | `kotlin.jvm.*` | только на JVM | Поэтому `println`, `listOf`, `Int` работают из коробки. А `kotlin.math.sqrt` - нет, его импортируют явно. ## Видимость на верхнем уровне ```kotlin public fun api() { } // видна везде (public — по умолчанию) internal fun moduleOnly() { } // видна в своём модуле private fun fileOnly() { } // видна только в этом файле ``` `protected` на верхнем уровне запрещён - нет класса, от которого наследоваться. Подробнее: [Модификаторы видимости](../../ООП/Модификаторы%20видимости.md) ## Имя класса-обёртки Функции верхнего уровня попадают в класс, названный по файлу: `Utils.kt` → класс `UtilsKt`. Имя можно задать: ```kotlin @file:JvmName("Utils") package com.example fun helper() { } // из Java: Utils.helper() ``` Аннотации уровня файла ставятся **до** `package`. Подробнее: [Kotlin из Java](../../Взаимодействие%20с%20Java/Kotlin%20из%20Java.md) > [!info] Отличия от Java > | Java | Kotlin | > |---|---| > | каталоги обязаны совпадать с пакетом | не обязаны (но так принято) | > | имя файла = имя публичного класса | имя файла произвольно | > | один публичный класс на файл | сколько угодно объявлений | > | `import static` для статики | обычный `import` для всего | > | псевдонимов нет | `import ... as Name` | > | автоимпорт только `java.lang` | десять пакетов `kotlin.*` | > | `package-private` по умолчанию | `public` по умолчанию | > > Последняя строка важна: в Java класс без модификатора виден только своему пакету, в Kotlin - всем. Для сокрытия внутренностей библиотеки используют `internal`. > [!warning] Подводные камни > **Нет аналога package-private.** `internal` ограничивает *модулем* (единицей компиляции Gradle), а не пакетом. Разделить код на пакеты и спрятать их друг от друга внутри одного модуля нельзя - только разносить по модулям. > > **`import *` не затягивает вложенные пакеты.** `import com.example.*` не даёт доступа к `com.example.data.User`. > > **Конфликт импортов - ошибка компиляции, а не предупреждение.** Два `User` из разных пакетов требуют `as` или полного имени. > > **Функции с одинаковым именем в разных файлах одного пакета конфликтуют.** Два `private fun helper()` в разных файлах - нормально, а два `fun helper()` с одной сигнатурой - ошибка: оба попадают в один пакет. > > **`@file:JvmName` не действует, если имя файла совпадает с именем класса в нём.** Коллизия имён вызовет ошибку компиляции. Дополнительно: [Структура проекта](../../Инструментарий/Структура%20проекта.md) Далее: [Null-безопасность](../Null-безопасность/Null-безопасность.md)