Подтвердить что ты не робот

Вызов суперкласс класса в Котлин, Супер не является выражением

У меня есть два класса Entity и Account как

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)
}
4b9b3361

Ответ 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()

Здесь я опустил конструкторы копирования и сделал абстрактные свойства, чтобы у дочернего класса были все свойства. Я также сделал дочерний класс a data class. Если вам нужно клонировать класс, вы можете просто вызвать account.copy().

Ответ 2

Используйте этот super<Entity>.fromEntity(entity) для вызова методов суперкласса.

Как говорится в документации:

В Kotlin наследование реализации регулируется следующим правилом: если класс наследует многие реализации одного и того же члена из его ближайших суперклассов, он должен переопределить этот член и предоставить свою собственную реализацию (возможно, используя один из унаследованных), Чтобы обозначить супертип, из которого берется наследованная реализация, мы используем супер-квалификацию по имени супертипа в угловых скобках, например. супер.

constructor(entity: Entity) : this() {
    super<Entity>.fromEntity(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)
        }
    }
}