7.0 KiB
title, description, tags
| title | description | tags | ||
|---|---|---|---|---|
| Пакеты и импорты | Объявление пакетов, импорты, псевдонимы и автоматически импортируемые пакеты |
|
Пакет
Объявляется первой строкой файла:
package com.example.app
fun helper() { }
class Service
Полное имя функции - com.example.app.helper.
Отличие от Java: структура каталогов не обязана совпадать с пакетом, и имя файла не связано с содержимым. Компилятор не возражает. На практике соглашение соблюдают: иначе навигация по проекту ломается.
Файл без package попадает в корневой пакет (default package).
Содержимое файла
В одном файле может быть сколько угодно объявлений верхнего уровня:
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 нет.
Импорты
import com.example.app.Service // конкретный класс
import com.example.app.helper // функция верхнего уровня
import com.example.app.* // всё из пакета
import com.example.app.User.Companion.create // член companion object
Импортировать можно не только типы, но и функции, свойства, enum-константы - всё, что объявлено на верхнем уровне или как статический член.
import kotlin.math.PI
import kotlin.math.sqrt
fun main() {
println(sqrt(PI)) // 1.7724538509055159
}
Псевдонимы - as
Когда имена конфликтуют или слишком длинные:
import com.example.data.User as DataUser
import com.example.api.User as ApiUser
fun convert(u: DataUser): ApiUser = ApiUser(u.name)
Псевдоним действует только в своём файле. Если нужно имя на весь модуль - это typealias.
Импортируются автоматически
Эти пакеты доступны без 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 - нет, его импортируют явно.
Видимость на верхнем уровне
public fun api() { } // видна везде (public — по умолчанию)
internal fun moduleOnly() { } // видна в своём модуле
private fun fileOnly() { } // видна только в этом файле
protected на верхнем уровне запрещён - нет класса, от которого наследоваться.
Подробнее: Модификаторы видимости
Имя класса-обёртки
Функции верхнего уровня попадают в класс, названный по файлу: Utils.kt → класс UtilsKt. Имя можно задать:
@file:JvmName("Utils")
package com.example
fun helper() { } // из Java: Utils.helper()
Аннотации уровня файла ставятся до package. Подробнее: Kotlin из Java
[!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не действует, если имя файла совпадает с именем класса в нём. Коллизия имён вызовет ошибку компиляции.
Дополнительно: Структура проекта Далее: Null-безопасность