一杯美式搞懂 Any、Unit、Nothing

三个火枪手

Kotlin 的类型系统不只是"变量能装什么值"这么简单,它还通过几个特殊类型把整个类型层级补齐了。

除了常见的数字、字符串、集合,AnyUnitNothing 这三个类型分别站在类型金字塔的顶部、中间语义位(无返回值)和底部位置。

理解它们之后,你会更容易写出语义清晰、类型推断更友好的 Kotlin 代码。

根:Any

在 Kotlin 中,每个类都会隐式继承自 Any

这意味着 Any 是所有非空类型的"最终父类型"(supertype),角色上接近 Java 的 java.lang.Object

因此,Any 类型的变量可以容纳任意类型的值:StringInt、自定义 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)。

相关推荐
黄林晴2 小时前
你的 Android App 还没接 AI?Gemini API 接入全攻略
android
恋猫de小郭12 小时前
2026 Flutter VS React Native ,同时在 AI 时代 VS Native 开发,你没见过的版本
android·前端·flutter
冬奇Lab13 小时前
PowerManagerService(上):电源状态与WakeLock管理
android·源码阅读
BoomHe18 小时前
Now in Android 架构模式全面分析
android·android jetpack
二流小码农1 天前
鸿蒙开发:上传一张参考图片便可实现页面功能
android·ios·harmonyos
鹏程十八少1 天前
4.Android 30分钟手写一个简单版shadow, 从零理解shadow插件化零反射插件化原理
android·前端·面试
Kapaseker1 天前
一杯美式搞定 Kotlin 空安全
android·kotlin
三少爷的鞋1 天前
Android 协程时代,Handler 应该退休了吗?
android
火柴就是我2 天前
让我们实现一个更好看的内部阴影按钮
android·flutter