Files
obsidian/Kotlin/Синтаксис и типы/Базовый синтаксис/Пакеты и импорты.md
T

132 lines
7.2 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
---
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`.
>
> Сравнить: [Модификаторы в Java](../../../Программирование%20на%20Java/ООП/Инкапсуляция/Модификаторы.md)
> [!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)