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

Kotlin中Box<T>类构造函数参数组合合法性校验

Kotlin 泛型类 Box<T> 实现方案

需求概述

需要实现一个泛型类Box<T>,包含两个公开不可变属性:

  • isContentMandatory: Boolean
  • content: T?

属性合法组合规则如下:

isContentMandatorycontent是否允许?
falsenull是
false非null是
truenull否
true非null是

要求:

  1. 构造函数不能生成非法状态的对象
  2. 提供多种便捷实例化方式,合法与非法示例参考:
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)                    // 禁止
  1. 非法实例化优先在编译期禁止,否则运行时抛出异常

方案一:构造函数校验(接近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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.25 02:24:13