155 lines
6.4 KiB
Markdown
155 lines
6.4 KiB
Markdown
---
|
||
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)
|