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

如何正确重载Kotlin数据类构造器?嵌套类访问问题求助

Kotlin 实现包含多备选类型的主数据类及便捷访问

原代码问题分析

  1. 构造器循环错误:次构造器constructor(person: Person, activity: Activity): this(person, activity)中,第二个参数是Activity类型,但主构造器要求的是Transport类型,编译器找不到匹配的主构造器,会误判为递归调用当前次构造器,导致循环调用链错误。
  2. 无法便捷访问嵌套对象:User类仅定义了person和transport属性,没有activity或absent属性,自然无法直接通过x.activity.game访问。

解决方案:使用密封类统一备选类型

密封类适合这种有限数量的备选类型场景,能确保所有可能的类型都被覆盖,同时配合自定义属性实现便捷访问。

完整代码示例

// 用密封类封装所有备选状态类型
sealed class UserStatus {
    data class Activity(val game: String, val funLevel: Int) : UserStatus()
    data class Absent(val isSick: Boolean, val funLevel: Int) : UserStatus()
    data class Transport(val typeOfTransport: String) : UserStatus()
}

data class Person(val name: String, val age: Int)

data class User(val person: Person, val status: UserStatus) {
    // 便捷访问属性:仅当status为对应类型时返回实例,否则抛出ClassCastException
    val activity: UserStatus.Activity
        get() = status as UserStatus.Activity

    val absent: UserStatus.Absent
        get() = status as UserStatus.Absent

    val transport: UserStatus.Transport
        get() = status as UserStatus.Transport

    // 可选:添加重载构造器简化对象创建
    constructor(person: Person, game: String, funLevel: Int) : this(person, UserStatus.Activity(game, funLevel))
    constructor(person: Person, isSick: Boolean, funLevel: Int) : this(person, UserStatus.Absent(isSick, funLevel))
    constructor(person: Person, typeOfTransport: String) : this(person, UserStatus.Transport(typeOfTransport))
}

fun main() {
    // 两种创建方式都支持
    val x = User(Person("foo", 5), UserStatus.Activity("basketball", 10))
    val y = User(Person("bar", 6), true, 0) // 使用重载构造器
    val z = User(Person("loo", 6), "Bus")

    // 实现便捷访问
    println(x.person.name)
    println(x.activity.game) // 输出:basketball
    println(y.absent.isSick) // 输出:true
    println(z.transport.typeOfTransport) // 输出:Bus
}

关键细节说明

  • 密封类UserStatus:将Activity、Absent、Transport统一为其子类,确保User的status属性只能是这三种类型之一,避免非法类型传入。
  • 自定义便捷属性:通过类型转换,直接暴露对应类型的属性,实现x.activity这类直观访问。如果需要更安全的访问(避免类型转换异常),可以改为返回可空类型:
    val activity: UserStatus.Activity?
        get() = status as? UserStatus.Activity
    
  • 重载构造器:简化User对象的创建过程,无需手动构建UserStatus子类实例。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.13 20:25:26