三个火枪手
Kotlin 的类型系统不只是"变量能装什么值"这么简单,它还通过几个特殊类型把整个类型层级补齐了。
除了常见的数字、字符串、集合,Any、Unit、Nothing 这三个类型分别站在类型金字塔的顶部、中间语义位(无返回值)和底部位置。
理解它们之后,你会更容易写出语义清晰、类型推断更友好的 Kotlin 代码。

根:Any
在 Kotlin 中,每个类都会隐式继承自 Any。
这意味着 Any 是所有非空类型的"最终父类型"(supertype),角色上接近 Java 的 java.lang.Object。
因此,Any 类型的变量可以容纳任意类型的值:String、Int、自定义 data class,甚至 lambda 表达式。
kotlin
fun printValue(value: Any) {
println("The value is: $value")
}
printValue("Hello, Kotlin") // 输出: The value is: Hello, Kotlin
printValue(123) // 输出: The value is: 123
printValue(User("RockByte")) // 输出: The value is: User(name=RockByte)
val lambdaAny: Any = { name: String ->
"Hello, $name! 这是一个存放在 Any 里的 Lambda。"
}
Any 还定义了所有对象都具备的 3 个基础方法:equals()、hashCode()、toString()。
kotlin
/**
* Kotlin 中所有类的最终父类型。
*
* 若要正确工作,自定义实现通常应满足这些规则:
* * 1. 任意对象都应等于它自身。
* * 2. 若 `a.equals(b)` 为 true,则 `b.equals(a)` 也必须为 true。
* * 3. 若 `a.equals(b)` 与 `b.equals(c)` 都为 true,则 `a.equals(c)` 也必须为 true。
* * 4. 在 `a` 与 `b` 未变化时,`a.equals(b)` 的结果应保持稳定。
* * 5. 任意对象都不应等于 `null`。
*/
public actual open class Any {
/**
* 判断当前对象是否与另一个对象在语义上"相等"。
*/
public actual open operator fun equals(other: Any?): Boolean
/**
* 返回对象的哈希值。
*
* 该值常用于 `HashMap` 等集合,以便快速存取。
* 两条关键规则:
* 1. 若两个对象相等(`a.equals(b)`),它们必须拥有相同的哈希值。
* 2. 对同一对象重复调用 `hashCode()`,只要属性不变,结果就应一致。
*/
public actual open fun hashCode(): Int
/**
* 返回对象的文本描述。
*
* 在日志与调试场景里非常有用。
*/
public actual open fun toString(): String
}
另外,Kotlin 还有可空版本 Any?,实际上,它才是"包含可空类型在内的所有类型"的真正根类型。
也就是说,Any? 既能放普通值,也能放 null。
无意义:Unit
很多语言里,函数不返回值会写成 void。
在 Kotlin 中,对应概念是 Unit。凡是"执行完了,但不产出有意义结果"的函数,都可以看作返回 Unit。
kotlin
fun showMessage(message: String): Unit {
println(message)
}
// Unit 返回类型可选,可以省略
fun showMessageImplicit(message: String) {
println(message)
}
和 Java 的 void 不同,Unit 是一个真实类型,并且由单例对象表示。这让它在泛型中更实用:比如你可以把 Unit 当作类型参数传递,而 void 做不到这一点。
kotlin
interface Processor<T> {
fun process(): T
}
class UnitProcessor : Processor<Unit> {
override fun process() {
// 函数会隐式返回 Unit
println("Processing complete, no value returned.")
}
}
Unit 的内部实现可以理解为一个只有单值(Unit 对象本身)的类型:
kotlin
/**
* 只有一个取值的类型:`Unit` 对象。该类型对应 Java 中的 `void`。
*/
public actual object Unit {
override fun toString(): String = "kotlin.Unit"
}
从语义上看,Unit 表达的是:函数的重点在副作用(例如打印日志、修改状态),而不是返回结果值。
虚空:Nothing
Nothing 是 Kotlin 类型系统里很关键也很有意思的概念。它表示"永远不可能存在的值",因此不存在任何 Nothing 实例,也无法创建 Nothing 类型变量的实际值。
它主要有两个用途:
1. 标记"函数不会正常返回"
如果一个函数只会抛异常,或者进入无限循环,它可以声明返回 Nothing。
这既能告诉编译器,也能让代码阅读者马上理解控制流不会继续往下走。
kotlin
fun fail(message: String): Nothing {
throw IllegalArgumentException(message)
}
fun infiniteLoop(): Nothing {
while (true) {
// 这个循环不会结束。
}
}
当编译器看到调用了返回 Nothing 的函数,就会把后续代码判定为不可达,从而做更准确的类型推断和控制流分析。
2. 作为类型层级的底部
Nothing 是所有类型的子类型 (包括 Any),也就是"底类型",这个特性在类型推断里很有价值。比如标准库中的 emptyList() 返回 List<Nothing>:
kotlin
val s: List<String> = emptyList() // OK: List<Nothing> -> List<String>
// 不会返回的函数使用 Nothing:
fun fail(): Nothing = throw IllegalStateException()
// `throw` 的类型是 Nothing,因此表达式依然类型成立:
val x: String = if (condition) "ok" else throw RuntimeException()
emptyList() 的具体实现如下,很多开发者可能没有注意到这一点:
Kotlin
internal object EmptyList : List<Nothing>
因为 List<Nothing> 保证"没有元素",所以它可以安全赋给任意 List<T>(如 List<String>、List<Int>)。这符合"该容器只包含 T 类型元素"的约束------因为它一个元素都没有。
而且,Nothing 本身也不能被实例化,内部定义类似这样:
kotlin
/**
* Nothing 没有实例。你可以用 Nothing 表示
* "永远不会存在的值",例如:
* 若函数返回类型为 Nothing,
* 则表示它不会返回(通常总是抛出异常)。
*/
public actual class Nothing private constructor()
小结
在 Kotlin 里:
Any是通用父类型,承载"所有值"的上界语义;Unit表示函数执行完成但不返回有意义结果;Nothing表示"不可能存在的值",常用于不可达控制流和底类型推断。
这三个类型共同把 Kotlin 的类型系统边界定义得非常清晰:顶部(Any)到中间语义位(Unit)再到底部(Nothing)。