You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何用Kotlin实现非空类型的静态属性(匹配给定Java实现)

问题:将Java单例式静态属性转为Kotlin非空类型实现

原始Java代码

private static Book currentBook;

public static Book get() {
    if(currentBook == null) {
        currentBook = new Book();
    }
    return currentBook;
}

public static void set(Book book) {
    if(currentBook != null) {
        throw new IllegalStateException();
    }
    currentBook = book;
}

我的Kotlin尝试实现

companion object {
    var currentBook: Book? = null
        get(): Book? {
            if (field == null) {
                field = Book()
            }

            return field
        }
    
        set(value) {
            if(field != null) {
                throw IllegalStateException()
            } 
            field = value
        }
}

困惑点

currentBook实际上始终是非空的,但为了允许默认初始化为null,必须将其类型声明为可空的Book?。请问有没有合适的方法让静态属性currentBook的类型为非空的Book?


惯用Kotlin实现方案

方案一:使用lateinit延迟初始化

利用lateinit允许非空变量延迟初始化的特性,结合私有内部变量和对外暴露的非空属性来实现逻辑:

companion object {
    // 私有延迟初始化变量,存储实际实例
    private lateinit var _currentBook: Book

    // 对外暴露的非空属性,通过getter实现懒加载
    val currentBook: Book
        get() {
            if (!::_currentBook.isInitialized) {
                _currentBook = Book()
            }
            return _currentBook
        }

    // 替代原set方法,实现初始化校验逻辑
    fun setCurrentBook(book: Book) {
        if (::_currentBook.isInitialized) {
            throw IllegalStateException()
        }
        _currentBook = book
    }
}

方案说明

  • 私有变量_currentBook用lateinit修饰,不需要初始化为null,保持非空类型
  • 对外的currentBook是只读非空属性,在getter中判断是否已初始化,未初始化则创建实例,确保返回值始终非空
  • 单独的setCurrentBook方法实现原Java中set的逻辑:如果已初始化则抛出异常,否则设置实例

方案二:使用Delegates.notNull()

如果不想用lateinit,可以借助Delegates.notNull()来实现非空延迟初始化,需要额外标记变量跟踪初始化状态:

import kotlin.properties.Delegates

companion object {
    private var _currentBook: Book by Delegates.notNull()
    private var isInitialized = false

    val currentBook: Book
        get() {
            if (!isInitialized) {
                _currentBook = Book()
                isInitialized = true
            }
            return _currentBook
        }

    fun setCurrentBook(book: Book) {
        if (isInitialized) {
            throw IllegalStateException()
        }
        _currentBook = book
        isInitialized = true
    }
}

方案对比

  • lateinit方案更简洁,不需要额外的状态标记变量,直接通过::属性.isInitialized判断初始化状态
  • Delegates.notNull()方案适合需要更灵活委托逻辑的场景,但需要手动维护初始化状态

内容的提问来源于stack exchange,提问作者citizen_code

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.14 21:18:13