【问题标题】:Call super class constructor in Kotlin, Super is not an expressionKotlin中调用超类构造函数,Super不是表达式
【发布时间】:2017-06-11 07:10:15
【问题描述】:

我有两个班级 EntityAccount

abstract class Entity(
    var id: String? = null,
    var created: Date? = Date()) {

    constructor(entity: Entity?) : this() {
        fromEntity(entity)
    }

    fun fromEntity(entity: Entity?): Entity {
        id = entity?.id
        created = entity?.created
        return this;
    }
}

data class Account( 
    var name: String? = null,
    var accountFlags: Int? = null
) : Entity() {

    constructor(entity: Entity) : this() {
        super(entity)
    }
}

这给了我错误

Super 不是表达式,它只能用在 一个点“。”

为什么我不能这样做?

下面会通过编译错误,但不知道是否正确。

 constructor(entity: Entity) : this() {
    super.fromEntity(entity)
}

【问题讨论】:

  • 您可以在此处找到如何调用超级 ctor 的规则:kotlinlang.org/docs/reference/classes.html#inheritance。简而言之,如果超类有一个主构造函数,则必须从基类的所有构造函数中调用它。
  • constructor(entity: Entity) : super(entity)
  • @zsmb13 你能分享一些代码吗?
  • @Miha_x64 我已经试过了,它给了Primary constructor call is expected

标签: kotlin


【解决方案1】:

您的代码中有几个问题。

首先,这是从二级构造函数调用超级构造函数的正确语法:

constructor(entity: Entity) : super(entity)

其次,如果你的类有一个主构造函数(你的类有),你就不能从一个辅助构造函数调用一个超级构造函数。

解决方案 1

abstract class Entity(
        var id: String,
        var created: Date
)

class Account(
        var name: String,
        var accountFlags: Int,
        id: String,
        created: Date
) : Entity(id, created) {
    constructor(account: Account) : this(account.name, account.accountFlags, account.id, account.created)
}

这里,复制构造函数在子类中,它只是委托给主构造函数。

解决方案 2

abstract class Entity(
        var id: String,
        var created: Date
) {
    constructor(entity: Entity) : this(entity.id, entity.created)
}

class Account : Entity {
    var name: String
    var accountFlags: Int

    constructor(name: String, accountFlags: Int, id: String, created: Date) : super(id, created) {
        this.name = name
        this.accountFlags = accountFlags
    }

    constructor(account: Account) : super(account) {
        this.name = account.name
        this.accountFlags = account.accountFlags
    }
}

这里我只在子类中使用辅助构造函数,这让我可以将它们委托给单独的超级构造函数。注意代码很长。

解决方案 3(最惯用的)

abstract class Entity {
    abstract var id: String
    abstract var created: Date
}

data class Account(
        var name: String,
        var accountFlags: Int,
        override var id: String,
        override var created: Date
) : Entity()

这里我省略了复制构造函数并将属性抽象化,因此子类具有所有属性。我还将子类设为data class。如果需要克隆类,可以直接调用account.copy()

【讨论】:

  • 谢谢。我已经尝试过constructor(entity: Entity) : super(entity) 的语法,但它给出了同样的错误super is not an expression... 我没有尝试你建议的代码,但我有一个问题。如果我必须在每个孩子中再次定义相同的字段,那么拥有父母有什么好处?
  • 就像我在回答中所说的那样,“如果您的类有主构造函数,则不能从辅助构造函数调用超级构造函数”。关于您的担忧,子类没有相同的字段。它具有传递给定义属性的超类的构造函数参数。
  • 如果我从孩子中删除了主构造函数,我可以调用父构造函数吗?你能用示例代码更新你的答案吗?
  • @AmrElAdawy 我已经用另外两个解决方案更新了我的答案。
  • 感谢您的更新。我会为这些努力投票。我仍然对解决方案有很多担忧。他们需要失去data 的性质,并且仍然需要在子项中添加父字段,我可以通过完全删除父项来避免。我仍然看到我的问题的编码较少。
【解决方案2】:

您也可以像这样将主构造函数向下移动到类中:

data class Account: Entity {
    constructor(): super()
    constructor(var name: String? = null, var accountFlags: Int? = null): super()
    constructor(entity: Entity) : super(entity)
}

这样做的好处是,编译器不会要求你的辅助构造函数调用主构造函数。

【讨论】:

    【解决方案3】:

    另一种选择是创建伴随对象并提供工厂方法,例如

    class Account constructor(
            var name: String? = null,
            var accountFlags: Int? = null,
            id: String?,
            created: Date?
    ) : Entity(id, created) {
    
        companion object {
            fun fromEntity(entity: Entity): Account {
                return Account(null, null, entity.id, entity.created)
            }
        }
    }
    

    【讨论】:

      【解决方案4】:

      使用此super<Entity>.fromEntity(entity) 调用超类方法。

      正如文档所说:

      在 Kotlin 中,实现继承受以下规则的约束:如果一个类从其直接超类继承同一成员的多个实现,则它必须覆盖该成员并提供自己的实现(也许,使用继承的一个) .为了表示继承实现的超类型,我们使用由尖括号中的超类型名称限定的 super,例如超级棒。

      constructor(entity: Entity) : this() {
          super<Entity>.fromEntity(entity)
      }
      

      了解更多请阅读Overriding Rules

      【讨论】:

      • 感谢您的回复。我知道表示超类型。但这实际上是一种解决方法。我想使用超级构造函数。
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2019-04-11
      相关资源
      最近更新 更多