如何用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
相关产品推荐
相关产品推荐

