Kotlin 中companion object {} 什么时候触发

[复制链接]
发表于 2025-6-26 16:28:01 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
在 Kotlin 中,companion object 的初始化触发时机是一个重要但容易被忽视的细节。以下是详细的解释:

1. 基本触发时机

companion object 的初始化发生在:


  • 首次访问该类时(无论是访问伴生对象成员、创建类实例,照旧通过反射访问类)
  • 类似于 Java 的静态初始化块,但更机动
    1. class MyClass {
    2.     companion object {
    3.         init {
    4.             println("Companion object 初始化!")
    5.         }
    6.         val CONST = "Hello"
    7.     }
    8. }
    9. fun main() {
    10.     println("程序启动")
    11.     MyClass.CONST  // 第一次访问 MyClass 时触发初始化
    12. }
    复制代码

 输出:
步伐启动
Companion object 初始化!

2. 详细触发场景

以下操作都会触发 companion object 初始化:
(1) 直接访问伴生对象成员

MyClass.CONST          // 触发
MyClass.Companion      // 触发
(2) 创建类实例

val obj = MyClass()    // 触发
(3) 通过反射访问类

MyClass::class          // 触发(Kotlin 反射)
(4) 访问类的其他声明

MyClass::class          // 触发(Kotlin 反射)

3. 不会触发的环境

以下操作不会触发初始化:
  1. // 仅声明类型(未实际访问)
  2. val clazz: Class<MyClass> = MyClass::class.java  
  3. // 作为类型参数(未实例化或访问)
  4. fun process(clazz: Class<*>) {}
  5. process(MyClass::class.java)  // 不会触发
复制代码
4. 与 Java 静态初始化的对比


特性Kotlin companion objectJava static 块初始化时机首次访问类时类加载时懒加载是(按需初始化)否(类加载时强制初始化)线程安全是(JVM 保证)是
5. 实际应用中的注意事项


(1) 性能优化

  1. class HeavyInitialization {
  2.     companion object {
  3.         val HEAVY_RESOURCE = loadResource() // 避免在伴生对象中放重型初始化
  4.     }
  5. }
  6. // 改为懒加载
  7. class BetterApproach {
  8.     companion object {
  9.         val heavyResource by lazy { loadResource() }
  10.     }
  11. }
复制代码
(2) 循环依赖问题

  1. class A {
  2.     companion object {
  3.         val VALUE = B.VALUE  // 如果 B 的伴生对象也依赖 A,会导致栈溢出
  4.     }
  5. }
  6. class B {
  7.     companion object {
  8.         val VALUE = A.VALUE
  9.     }
  10. }
复制代码
办理方案:利用 lazy 延迟初始化
  1. class A {
  2.     companion object {
  3.         val VALUE by lazy { B.VALUE }
  4.     }
  5. }
复制代码
6. 验证示例

  1. class Test {
  2.     companion object {
  3.         init { println("伴生对象初始化") }
  4.     }
  5.    
  6.     init { println("类实例初始化") }
  7. }
  8. fun main() {
  9.     println("阶段1")
  10.     Test::class  // 仅访问 KClass,不触发
  11.    
  12.     println("阶段2")
  13.     Test.Companion // 触发初始化
  14.    
  15.     println("阶段3")
  16.     Test() // 伴生对象已初始化,不会再次触发
  17. }
复制代码
输出:
阶段1
阶段2
伴生对象初始化
阶段3
类实例初始化

总结




  • companion object 在首次真正利用类时初始化(懒加载)
  • 比 Java 的静态初始化更机动,但逻辑相似
  • 适合存放类级别的常量、工厂方法等
  • 避免在伴生对象中直接举行重型操作,建议用 by lazy

回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表