Kotlin 数据类型
Kotlin 是静态类型语言——每个变量在编译期就有确定的类型。本篇系统讲解所有内置数据类型:数值、布尔、字符、字符串、数组,以及 Kotlin 特殊的 Unit/Nothing/Any。
1. 数值类型(Byte/Short/Int/Long/Float/Double)
Kotlin 的数值类型和 Java 一脉相承,有固定的位宽:
// 整数类型(位宽从大到小:Long > Int > Short > Byte)
val a: Byte = 8 // 8 位,-128 ~ 127
val b: Short = 1000 // 16 位,-32768 ~ 32767
val c: Int = 100000 // 32 位,-2^31 ~ 2^31-1
val d: Long = 100L // 64 位,字面量加 L 后缀
// 浮点类型
val e: Float = 2.5f // 32 位,字面量加 f 后缀
val f: Double = 3.14 // 64 位,默认推断类型
// 字面量下划线(提高可读性)
val million = 1_000_000
val bytes = 0xFF_FF_FF_FF
// 数值类型【都是对象】(包装类)
// Int 在 JVM 上编译为 int(基本类型)和 Integer(装箱)几个关键点:
- 整型位宽:Byte(8)、Short(16)、Int(32)、Long(64)。
- 浮点位宽:Float(32)、Double(64,默认)。
- 字面量后缀:Long 加
L,Float 加f。十六进制0xFF,二进制0b1010。 - 下划线:数字字面量可以用下划线分组提高可读性:
1_000_000。 - 所有类型都是对象:Kotlin 没有 Java 那种
int(基本)和Integer(装箱)的两套系统。但在 JVM 后端,Kotlin 编译器会自动用 Java 基本类型优化(性能等同 Java),只有可空Int?才会装箱。
2. 类型转换(重要!)
这是 Kotlin 和 Java 一个关键差异:Kotlin 不支持隐式类型转换。Java 里 long b = a;(a 是 int)能编译,Kotlin 不行:
// Kotlin 【不支持隐式类型转换】(和 Java 不一样!)
val a: Int = 10
// val b: Long = a // 编译错误
val b: Long = a.toLong() // OK,显式转换
// 所有数值类型都有 toXxx() 方法
val i: Int = 42
i.toLong()
i.toDouble()
i.toFloat()
i.toShort()
i.toByte()
// 字符串转数值(注意是 toIntOrNull,不抛异常)
val s = "42"
val n: Int? = s.toIntOrNull() // 42
val bad: Int? = "abc".toIntOrNull() // null
// 强制转换会截断
val big: Long = 1_000_000_000_000L
val trunc: Int = big.toInt() // 截断!结果不可预期设计理由:避免精度丢失的隐性 bug。Java 里 int a = 1000; byte b = (byte) a; 静默截断成 -24,Kotlin 强制你显式 .toByte() 才能这么做。所有数值类型都有 toLong()、toInt()、toDouble() 等方法互转。
3. 布尔类型(Boolean)
Boolean 只有两个值,逻辑运算和大多数语言一致:
// Boolean 只有两个值:true / false
val ok: Boolean = true
val done = false // 类型推断为 Boolean
// 逻辑运算符
val a = true
val b = false
println(a && b) // false,短路
println(a || b) // true,短路
println(!a) // false
// 比较运算符返回 Boolean
println(3 > 2) // true
println("a" == "a") // true(值相等,类似 Java equals)
println("a" === "a") // 引用相等(通常 true,但不保证)注意 Kotlin 的 == 等价于 Java 的 equals()(值相等),=== 才是引用相等。所以两个内容一样的字符串 == 返回 true(Java 里恰好也成立,因为字符串池,但不保证)。
4. 字符类型(Char)
Char 表示单个 Unicode 字符,用单引号包裹(字符串用双引号):
// Char:单个 Unicode 字符,用单引号
val c1: Char = 'A'
val c2 = '中' // 中文也合法
val newline = '\n' // 换行符
val tab = '\t' // Tab
// 转义字符
val quote = '\'' // 单引号
val backslash = '\\' // 反斜杠
// Char 不能直接当数字用(和 Java 不一样)
// val code: Int = 'A' // 编译错误!
val code: Int = 'A'.code // 65,显式调用 code
val ch = 65.toChar() // 'A',数字转字符Kotlin 的 Char 不能直接当数字用——这是和 Java/C 的关键区别。要拿 ASCII 码必须调 .code。理由:Char 是字符不是数字,Kotlin 在类型层面把这两者严格分开。
5. 字符串(String)
String 是 Kotlin 用得最多的类型之一,支持模板插值和多行字符串:
// String:字符串,双引号
val s1: String = "hello"
val s2 = "你好"
// 字符串模板
val name = "小明"
val greeting = "你好, $name"
// 多行字符串(原始字符串):三个引号
val text = """
第一行
第二行
第三行
"""
// 默认带缩进,用 trimMargin() 去除
val clean = text.trimMargin()更多字符串操作请见专门的 字符串教程。
6. 数组(Array)
Kotlin 的 Array 是泛型类 Array<T>,但不推荐常用——大多数场景应该用 List/Map 等集合类型,API 更友好。数组主要用于:
- 性能敏感场景(配合
IntArray、ByteArray等不装箱)。 - 需要和 Java 代码交互(Java API 接收数组)。
- 固定大小的高性能缓冲区。
// Array:数组,固定大小,可以装任意类型
val nums = arrayOf(1, 2, 3, 4, 5)
println(nums.size) // 5
println(nums[0]) // 1
nums[0] = 100 // 修改元素
// 数组类型 vs 集合类型(推荐用集合)
// Array<Int> 装箱,IntArray 不装箱(性能更好)
val primitive: IntArray = intArrayOf(1, 2, 3)
val boxed: Array<Int> = arrayOf(1, 2, 3)
// 其他基本类型数组(为了性能)
val bytes = byteArrayOf(1, 2, 3)
val longs = longArrayOf(1L, 2L, 3L)
val doubles = doubleArrayOf(1.0, 2.0)
// 遍历
for ((index, value) in nums.withIndex()) {
println("[$index] = $value")
}IntArray vs Array<Int>:前者编译为 Java int[](无装箱,内存紧凑,性能优);后者是 Integer[](每个元素装箱,GC 压力大)。能用 IntArray 就别用 Array<Int>。
7. 特殊类型:Unit、Nothing、Any
这是 Kotlin 类型系统的几个"特殊存在",初学者容易混淆:
// Unit:类似 Java 的 void,但是是个真实类型
fun printGreeting(): Unit { // Unit 返回类型可省略
println("hi")
}
// Nothing:永远不会返回的函数(抛异常或无限循环)
fun fail(msg: String): Nothing {
throw IllegalArgumentException(msg)
}
// Any:所有非空类型的根(类似 Java 的 Object)
val obj: Any = "hello"
val num: Any = 42
// 类型判断 + 智能转换
if (obj is String) {
// 在这个分支里 obj 自动当作 String
println(obj.length) // 不需要强转
}
// 可空版本:Any? 是所有类型的根(包括可空)要点:
- Unit:类似 Java 的 void,但是个真实类型(只有一个实例
Unit)。函数没显式返回类型时默认返回 Unit。好处:类型系统统一,泛型可以用Unit当类型参数。 - Nothing:返回类型表示"函数永远不会正常返回"(抛异常或无限循环)。编译器据此做流分析,知道
fail()后面的代码不可达。 - Any:所有非空类型的根(类似 Java 的 Object,但更轻)。需要可空版本就用
Any?。
8. 类型判断与智能转换
Kotlin 的 is 运算符判断类型,而且会触发智能转换(smart cast)——编译器自动帮你窄化类型:
fun describe(x: Any): String =
when (x) {
is Int -> "整数 ${x + 1}" // x 自动当 Int
is String -> "字符串,长度 ${x.length}" // x 自动当 String
is List<*> -> "列表,大小 ${x.size}"
else -> "其他类型"
}
println(describe(42)) // 整数 43
println(describe("hello")) // 字符串,长度 5
println(describe(listOf(1,2))) // 列表,大小 2对比 Java 的 instanceof + 显式强转,Kotlin 这套机制干净得多。
小结
这一章你了解了 Kotlin 所有内置数据类型:数值(Byte/Short/Int/Long/Float/Double)、布尔、字符、字符串、数组,以及特殊的 Unit/Nothing/Any。也踩到了 Kotlin 不允许隐式类型转换的坑——这是初学者最容易出错的地方。下一篇我们看运算符——这些类型怎么相互运算。
← 上一篇 Kotlin 变量
下一篇 Kotlin 运算符 →