Kotlin中Box<T>类构造函数参数组合合法性校验
Kotlin 泛型类
Box<T> 实现方案 需求概述
需要实现一个泛型类Box<T>,包含两个公开不可变属性:
isContentMandatory: Booleancontent: T?
属性合法组合规则如下:
| isContentMandatory | content | 是否允许? |
|---|---|---|
| false | null | 是 |
| false | 非null | 是 |
| true | null | 否 |
| true | 非null | 是 |
要求:
- 构造函数不能生成非法状态的对象
- 提供多种便捷实例化方式,合法与非法示例参考:
Box() // 合法 -> isContentMandatory = false, content = null Box("some-content") // 合法 -> isContentMandatory = false, content = "some-content" Box(false, "some-content") // 合法 -> isContentMandatory = false, content = "some-content" Box(true, "some-content") // 合法 -> isContentMandatory = true, content = "some-content" Box(true, null) // 禁止 Box(true) // 禁止
- 非法实例化优先在编译期禁止,否则运行时抛出异常
方案一:构造函数校验(接近Java实现)
该方案逻辑与你提供的Java实现对齐,通过主构造函数做合法性校验,次构造函数提供便捷实例化入口。
代码实现
class Box<T> private constructor( val isContentMandatory: Boolean, val content: T? ) { // 无参次构造:对应 isContentMandatory=false, content=null constructor() : this(false, null) // 仅传content的次构造:对应 isContentMandatory=false constructor(content: T?) : this(false, content) init { // 运行时校验非法组合 if (isContentMandatory && content == null) { throw IllegalArgumentException("当isContentMandatory为true时,content不能为null") } } }
关键概念解释
- 主构造函数:Kotlin类可在类名后直接定义主构造,这里标记为
private,仅允许内部或次构造调用,避免外部直接传入非法参数组合。 - 次构造函数:用
constructor关键字定义,必须直接或间接调用主构造。这里提供无参和仅传content的两个次构造,覆盖便捷实例化场景。 - init代码块:主构造执行时会触发
init块,在此完成参数合法性校验,非法组合直接抛出运行时异常。
限制
此方案下,Box(true, null)在编译期不会报错,仅能在运行时拦截非法组合。
方案二:伴生对象工厂方法(编译期禁止非法实例)
利用Kotlin伴生对象提供工厂方法,通过函数签名设计,从编译期层面阻止非法实例化。
代码实现
class Box<T> private constructor( val isContentMandatory: Boolean, val content: T? ) { // 伴生对象:等价于Java中的静态内部类,用于提供工厂方法 companion object { // 无参创建:isContentMandatory=false, content=null fun <T> empty(): Box<T> = Box(false, null) // 传入非null content,isContentMandatory=false fun <T> of(content: T): Box<T> = Box(false, content) // 强制要求非null content,isContentMandatory=true fun <T> mandatory(content: T): Box<T> = Box(true, content) // 允许传入可空content,isContentMandatory固定为false fun <T> optional(content: T?): Box<T> = Box(false, content) } }
使用示例
// 合法调用 val emptyBox = Box.empty<String>() val optionalBoxWithContent = Box.of("some-content") val mandatoryBox = Box.mandatory("must-have-content") val optionalBoxNull = Box.optional<String?>(null) // 编译期报错:mandatory方法参数为非可空类型,无法传入null // Box.mandatory(null) // 无直接调用Box(true, null)的方式,完全避免非法组合
关键概念解释
- 伴生对象:
companion object内的方法可直接通过类名调用(类似Java静态方法),所有实例化逻辑都封装在此。 - 编译期安全:通过工厂方法的参数类型约束,比如
mandatory方法参数为非可空T,从根源上杜绝isContentMandatory=true且content=null的非法组合。 - 语义化命名:
empty、of、mandatory、optional等命名比直接调用构造函数更清晰,符合Kotlin惯用写法。
优势
完全在编译期拦截非法实例化,无需运行时校验,同时工厂方法语义明确,使用更直观。
方案三:数据类+私有构造(简化不可变属性)
如果仅需纯数据容器,可使用Kotlin的data class简化实现,它会自动生成equals、hashCode、toString等方法。
data class Box<T> private constructor( val isContentMandatory: Boolean, val content: T? ) { companion object { fun <T> empty(): Box<T> = Box(false, null) fun <T> of(content: T): Box<T> = Box(false, content) fun <T> mandatory(content: T): Box<T> = Box(true, content) fun <T> optional(content: T?): Box<T> = Box(false, content) } }
内容的提问来源于stack exchange,提问作者sjakovac
相关产品推荐
相关产品推荐

