--- title: Типы данных description: Система типов Kotlin, числа, boolean, Char и отсутствие примитивов на уровне языка tags: - kotlin - types --- В Kotlin: статическая типизация, сильная, с выводом типов. Главное отличие от Java: **на уровне языка примитивов нет**. Всё - объект, у всего есть методы. ```kotlin val x: Int = 42 println(x.toString()) // у числа есть методы println(42.coerceIn(0, 10)) // 10 ``` Но в байт-коде `Int` компилируется в `int`, если это возможно - производительность не теряется. Подробнее в [Kotlin в байт-коде](../../Взаимодействие%20с%20Java/Kotlin%20в%20байт-коде.md). ## Иерархия типов ```mermaid graph TD Any["Any — корень всех non-null типов"] Any --> Number Any --> Char Any --> Boolean Any --> String Any --> Other["классы, интерфейсы, ..."] Number --> Byte Number --> Short Number --> Int Number --> Long Number --> Float Number --> Double Nothing["Nothing — наследник всех типов"] ``` `Any`, `Unit` и `Nothing` - особые типы, им посвящена отдельная заметка: [Any, Unit, Nothing](../Базовые%20типы%20ООП/Any,%20Unit,%20Nothing.md) ## Числовые типы | Тип | Размер, бит | Диапазон | |---|---|---| | `Byte` | 8 | −128 … 127 | | `Short` | 16 | −32 768 … 32 767 | | `Int` | 32 | ≈ ±2 млрд | | `Long` | 64 | ≈ ±9,2 · 10¹⁸ | | `Float` | 32 | ≈ 6-7 значащих цифр | | `Double` | 64 | ≈ 15-16 значащих цифр | Все наследуются от `Number`, но **не** друг от друга: `Int` не является подтипом `Long`. ### Литералы ```kotlin val i = 42 // Int по умолчанию val l = 42L // Long — суффикс L val d = 42.0 // Double по умолчанию val f = 42.0f // Float — суффикс f val hex = 0xFF // 255 val bin = 0b1010 // 10 val big = 1_000_000 // подчёркивания для читаемости ``` Восьмеричных литералов (`017` в Java) в Kotlin **нет**. ## Беззнаковые типы `UByte`, `UShort`, `UInt`, `ULong` - то, чего в Java нет совсем. ```kotlin val u: UInt = 4_000_000_000u // суффикс u println(UInt.MAX_VALUE) // 4294967295 ``` Нужны редко: работа с бинарными форматами, протоколами, хешами. ## Boolean ```kotlin val yes: Boolean = true val both = yes && other() // ленивые операторы, как в Java val eager = yes and other() // не ленивый: other() вызовется всегда ``` ## Char ```kotlin val c: Char = 'A' println(c.code) // 65 — числовой код println(c + 1) // B — Char + Int даёт Char println(c.isLetter()) // true ``` `Char` **не является числом**: `val n: Int = 'A'` не скомпилируется, нужен `'A'.code`. Подробнее: [Char](../Работа%20с%20данными/Char.md) ## Преобразования Неявных расширяющих преобразований нет вообще - только явные вызовы: ```kotlin val i = 42 val l: Long = i.toLong() // обязательно явно val b = i.toByte() val d = i.toDouble() ``` Доступны `toByte()`, `toShort()`, `toInt()`, `toLong()`, `toFloat()`, `toDouble()`, `toChar()`. ## Строки `String` - неизменяемый тип, элементы доступны по индексу: ```kotlin val s = "Kotlin" println(s[0]) // K println(s.length) // 6 ``` Подробнее: [Строки](../Работа%20с%20данными/Строки.md) ## Nullable-типы Любой тип имеет nullable-вариант с `?`: ```kotlin // val a: Int = null // ошибка компиляции val b: Int? = null // ok ``` Это ядро языка, ему посвящён отдельный раздел: [Null-безопасность](../Null-безопасность/Null-безопасность.md) > [!info] Отличия от Java > | Java | Kotlin | > |---|---| > | `int` и `Integer` - разные типы | только `Int`, компилятор сам выбирает представление | > | автоупаковка неявная | упаковка скрыта, в коде не видна | > | `long x = intValue;` работает | нужен `intValue.toLong()` | > | `char` - числовой тип | `Char` - отдельный тип, не число | > | нет беззнаковых типов | `UInt`, `ULong`, … | > | `017` - восьмеричный литерал | восьмеричных литералов нет | > > Сравнить: [Типы данных в Java](../../../Программирование%20на%20Java/Синтаксис%20и%20типы/Базовый%20синтаксис/Типы%20данных.md) > [!warning] Подводные камни > **Переполнение не проверяется**, как и в Java: > ```kotlin > println(Int.MAX_VALUE + 1) // -2147483648 > ``` > > **Равенство упакованных значений.** Если тип nullable, значение упаковано, и `===` сравнивает ссылки: > ```kotlin > val a: Int = 127 > val b: Int? = a > val c: Int? = a > println(b == c) // true — сравнение значений > println(b === c) // true — кеш Integer для -128..127 > > val x: Int? = 1000 > val y: Int? = 1000 > println(x == y) // true > println(x === y) // false — за пределами кеша это разные объекты > ``` > Вывод: для чисел всегда `==`, никогда `===`. > > **`Float` и `Double` не точны**, это стандарт IEEE 754: > ```kotlin > println(0.1 + 0.2) // 0.30000000000000004 > ``` > Для денег - `java.math.BigDecimal`. Дополнительно: [Числа и переполнение](../Работа%20с%20данными/Числа%20и%20переполнение.md) Далее: [Переменные](Переменные.md)