Kotlin 的 ‌init 代码块‌

Kotlin 的 ‌**init 代码块**‌是类初始化逻辑的核心部分,用于在对象创建时执行特定的初始化操作。以下是其核心知识点和典型用法:


基本特性

  1. 执行时机‌:

    • 在类实例化时,‌主构造函数调用后立即执行‌。
    • 与属性初始化器按代码中的‌声明顺序‌执行。
  2. 主要用途‌:

    • 初始化需要复杂逻辑的属性。
    • 验证构造函数参数的有效性。
    • 执行对象创建时的必要操作(如资源加载、日志记录)。

语法结构

kotlin 复制代码
class MyClass(param: String) {
    // 属性初始化器(直接赋值)
    val simpleProperty = param.uppercase()

    // init 代码块
    init {
        require(param.isNotEmpty()) { "参数不能为空" } // 参数校验
        println("对象已创建,参数为:$param")
    }

    // 另一个 init 块(按声明顺序执行)
    init {
        println("第二个初始化块")
    }
}

执行顺序

  1. 主构造函数参数 ‌ → ‌属性初始化器 ‌ → ‌**init‌ → ‌次构造函数体**‌(若有)。
  2. 多个 init 块按‌代码中的声明顺序‌依次执行。
  3. 若存在‌次构造函数 ‌,所有 init 块和属性初始化器会在次构造函数体之前执行。

示例‌:

kotlin 复制代码
class Person(val name: String) {
    val firstProperty = "第一个属性".also(::println)

    init {
        println("第一个 init 块")
    }

    val secondProperty = "第二个属性".also(::println)

    init {
        println("第二个 init 块")
    }

    constructor(name: String, age: Int) : this(name) {
        println("次构造函数体") // 最后执行
    }
}

// 输出:
// 第一个属性
// 第一个 init 块
// 第二个属性
// 第二个 init 块
// 次构造函数体

典型使用场景

1. ‌参数校验

javascript 复制代码
class User(name: String) {
    init {
        require(name.isNotBlank()) { "用户名不能为空" }
    }
}

2. ‌复杂属性初始化

kotlin 复制代码
class DatabaseConfig(url: String) {
    val connectionTimeout: Int

    init {
        connectionTimeout = parseTimeout(url) // 调用函数计算值
    }

    private fun parseTimeout(url: String): Int { /* ... */ }
}

3. ‌资源初始化

arduino 复制代码
class FileLoader(path: String) {
    private val file: File

    init {
        file = File(path)
        file.createNewFile() // 创建文件
    }
}

注意事项

  1. 避免访问未初始化的属性‌:

    kotlin 复制代码
    class Demo {
        val a = 1
        init {
            println(a)  // 正确:输出 1
            println(b)  // 错误!此时 b 尚未初始化
        }
        val b = 2
    }
  2. 与次构造函数的关系‌:

    • 所有 init 块和属性初始化器会在次构造函数体‌之前‌执行。
    • 次构造函数必须直接或间接委托给主构造函数。
    kotlin 复制代码
    class Person(val name: String) {
        init { println("主构造逻辑") }
    
        constructor() : this("默认名称") {
            println("次构造逻辑") // 在 init 块之后执行
        }
    }
  3. 异常处理‌:

    • init 块中可抛出异常,中断对象创建:
    arduino 复制代码
    class Validator(rule: String) {
        init {
            if (rule.contains("invalid")) throw IllegalArgumentException("非法规则")
        }
    }

与 Java 初始化块的对比

这个不是Java的 static{} 相当于是Java的 {} 构造代码块

特性 Kotlin init Java 实例初始化块
执行时机 主构造函数之后 构造函数之前
与构造函数关系 属于主构造函数的一部分 独立于构造函数
多个块执行顺序 按代码顺序执行 按代码顺序执行
参数访问 直接使用主构造函数参数 需通过构造函数参数赋值给字段

总结

  • 使用 init 的场景:

    • 需要‌在主构造函数中嵌入复杂逻辑‌时。
    • 确保对象创建时‌属性合法 ‌或‌资源就绪‌。
  • 避免 init 的场景:

    • 简单属性初始化(直接使用属性初始化器)。
    • 与次构造函数逻辑高度耦合时(优先将逻辑放在次构造函数体内)
相关推荐
河铃旅鹿2 小时前
Android开发-java版:SQLite数据库
android·数据库·笔记·学习·sqlite
旋律逍遥2 小时前
《Framework 开发》3、开发工具及命令行知识装备
android
啦啦9117142 小时前
安卓手机/平板/TV版 Rotation强制横屏显示工具!免ROOT可用!再推荐突破手机限制的3款神器
android·智能手机·电脑
汤面不加鱼丸3 小时前
flutter实践:混合app在部分android旧机型上显示异常
android·flutter
_李小白4 小时前
【Android FrameWork】延伸阅读:ActivityManagerService启动Activity
android
用户41659673693554 小时前
Android 媒体库高效扫描器:基于协程与 `ContentObserver` 的 `FileScanner`
android
Arenaschi4 小时前
Android中的release下面的包有什么左右和debug 的包有什么区别
android
stevenzqzq4 小时前
android recyclerview缓存2_四级缓存机制
android·spring boot·缓存
用户69371750013845 小时前
Kotlin 函数详解:命名参数与默认参数值
android·后端·kotlin
卓修武K5 小时前
Android系统BUG:修改线程名目标错乱问题探究
android