Kotlin之【init】—— 新手须知

在 Kotlin 中,init 块是初始化块,用于在类实例创建时执行额外的初始化逻辑。它属于类的主构造函数的一部分,在属性初始化器和主构造函数的参数之后、次构造函数的主体之前执行。

1. 基本语法

kotlin 复制代码
class MyClass {
    init {
        // 初始化代码
    }
}

可以定义多个 init 块,它们按照在类中出现的从上到下的顺序依次执行。

2. 执行时机与顺序

一个完整的初始化顺序是:

  1. 主构造函数的参数(仅作为形参,未转化为属性时)
  2. 类中定义的属性初始化器 (例如 val a = 10)
  3. init 块(若有多个,依次执行)
  4. 次构造函数的主体(如果通过次构造函数创建实例,且该构造器最终委托给主构造器)

示例:

kotlin 复制代码
class Person(name: String, age: Int) {
    val upperName = name.uppercase()   // ① 属性初始化

    init {
        println("第一个 init 块: name=$name, age=$age")
    }

    val greeting = "Hello, $upperName" // ② 另一个属性初始化

    init {
        println("第二个 init 块: greeting=$greeting")
    }

    constructor(name: String) : this(name, 0) {
        println("次构造函数主体")       // ③ 在 init 之后执行
    }
}

fun main() {
    val p = Person("Alice", 25)
}

输出:

text 复制代码
第一个 init 块: name=Alice, age=25
第二个 init 块: greeting=Hello, ALICE

如果使用次构造函数:Person("Bob"),输出会额外增加最后一行"次构造函数主体"。

3. 主要用途

  • 参数验证:检查传递给构造函数的参数合法性。
  • 进行无法在属性初始化器中完成的复杂计算。
  • 调用非 Kotlin 标准库的 API(如 Android 中的视图设置) 。
  • 在多个构造函数间共享初始化逻辑 (因为所有次构造函数最终都会委托给主构造器,init 块一定会执行)。

示例:参数验证

kotlin 复制代码
class User(email: String, password: String) {
    val email: String
    val password: String

    init {
        require(email.isNotBlank()) { "Email cannot be blank" }
        require(password.length >= 6) { "Password too short" }
        this.email = email.trim()
        this.password = password
    }
}

4. 与属性声明的关系

由于 init 块在属性初始化器之后执行,因此可以在 init 块中访问已经初始化的属性。但需要注意声明的顺序 :如果在 init 块中访问一个尚未初始化的属性(即属性初始化器在 init 块之后),编译器会报错。

kotlin 复制代码
class Demo {
    init {
        println(a)  // 错误:变量 'a' 必须被初始化
    }
    val a = 10
}

正确的做法是将 init 块放在需要访问的属性之后,或者保证该属性有默认值。

5. 与主构造函数参数的交互

主构造函数的参数可以在属性初始化器和 init 块中直接使用(前提是它们没有被 var/val 修饰成属性时,作用域仅限于初始化阶段)。如果想在类的方法中也使用参数,需要将参数声明为属性(val/var)。

kotlin 复制代码
class Rectangle(val width: Int, val height: Int) {
    val area: Int

    init {
        area = width * height   // width, height 可以直接使用
    }
}

6. 多个 init 块与属性初始化器的混合顺序

所有属性初始化器和 init 块共同形成初始化序列,顺序由代码中出现的位置决定。

kotlin 复制代码
class Example {
    val first = "First".also(::println)  // ①

    init {
        println("init 1")                // ②
    }

    val second = "Second".also(::println) // ③

    init {
        println("init 2")                // ④
    }
}
// 输出: First -> init 1 -> Second -> init 2

7. 注意事项

  • init 块不是构造函数,它不能拥有自己的参数,也不能被重载。
  • 如果一个类没有显式主构造函数(即只有次构造器),但仍然可以定义 init 块。此时没有主构造器的参数可用,但 init 块仍会在次构造函数委托给主构造函数时(隐式存在)执行。
  • init 块中可以使用 return,但只是提前退出块,不会阻止实例的创建(除非抛出异常)。

8. 与 Java 构造代码块对比

特性 Kotlin init 块 Java 实例初始化块
执行时机 属性初始化后,构造器主体前 属性初始化后,构造器主体前
是否可有多个 是 是
是否可见参数 可访问主构造参数 只能访问构造器参数(通过构造器传递)
使用场景 与主构造器紧密集成 与所有构造器共享代码

总结

  • init 块是 Kotlin 类初始化阶段的一部分,用于执行主构造函数的额外逻辑。
  • 它们按照定义顺序与属性初始化器交错执行。
  • 适用于参数验证、复杂初始化、以及在主构造器上下文中必须执行的代码。
  • 合理使用 init 块能让类初始化过程更加清晰和模块化。
相关推荐
aqi008 小时前
鸿蒙版本的电子书阅读APP开放源码啦
android·华为·ai编程·harmonyos·鸿蒙
墨天梦8 小时前
B19_SunnyWeather到阅读客户端
android·kotlin
美狐美颜sdk9 小时前
直播APP源码可以直接接入视频美颜sdk吗?技术方案详解
android·人工智能·音视频·美颜sdk·直播美颜sdk
用户693717500138411 小时前
2026,程序员的时代拐点到了
android·前端·后端
浪潮IT馆13 小时前
Android Studio 非最新版本下载安装教程
android·ide·android studio
xiaozongt198914 小时前
MasterGo + Claude Code 生成 Android 布局:完整实践指南
android
Anhty15 小时前
2026最新免费手机音频处理工具 !!
android·功能测试·ios·智能手机·音视频
2501_9159090617 小时前
iOS应用从开发到上架App Store的完整发布流程与步骤指南
android·ios·小程序·https·uni-app·webview
狗凯之家源码网18 小时前
AI 步数修改提交系统源码应用场景与落地指南
android·数据库·人工智能·运动步数
ZHOUPUYU18 小时前
PHP 9.0 前瞻:下一代 PHP 会带来哪些新功能?
android·开发语言·php