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 的场景:

    • 简单属性初始化(直接使用属性初始化器)。
    • 与次构造函数逻辑高度耦合时(优先将逻辑放在次构造函数体内)
相关推荐
飞猿_SIR2 小时前
Android Exoplayer 实现多个音视频文件混合播放以及音轨切换
android·音视频
HumoChen993 小时前
GZip+Base64压缩字符串在ios上解压报错问题解决(安卓、PC模拟器正常)
android·小程序·uniapp·base64·gzip
沙振宇7 小时前
【HarmonyOS】ArkTS开发应用的横竖屏切换
android·华为·harmonyos
橙子199110168 小时前
Kotlin 中的作用域函数
android·开发语言·kotlin
zimoyin8 小时前
Kotlin 懒初始化值
android·开发语言·kotlin
枣伊吕波9 小时前
第六节第二部分:抽象类的应用-模板方法设计模式
android·java·设计模式
萧然CS9 小时前
使用ADB命令操作Android的apk/aab包
android·adb
_extraordinary_13 小时前
MySQL 事务(二)
android·数据库·mysql
鸿蒙布道师17 小时前
鸿蒙NEXT开发动画案例5
android·ios·华为·harmonyos·鸿蒙系统·arkui·huawei
橙子199110161 天前
在 Kotlin 中什么是委托属性,简要说说其使用场景和原理
android·开发语言·kotlin