Kotlin/Java: переопределить абстрактное значение в конструкторе подкласса

Учитывая абстрактный класс:

abstract class BobaTea {
    abstract val sweetness: Int
}

У меня есть подкласс, в котором я хочу переопределить sweetness, однако я хочу сделать это в конструкторе, потому что значение сладости не может быть определено во время компиляции, я узнаю его только во время выполнения. Однако мой конструктор гарантирует, что все экземпляры подкласса действительно реализуют абстрактное значение sweetness.

class MatchaBobaLatte : BobaTea() {
    constructor(sweetness: Int) : this() {
        this.sweetness = sweetness  // This fails with "val cannot be reassigned"
    }
}

Почему это не работает? Я не переназначаю sweetness, я просто переопределяю его, потому что он абстрактен в суперклассе.

Спасибо.

Я не знаю Kotlin, но в Java абстрактные методы должны быть объявлены конкретно, прежде чем их можно будет использовать. Поскольку ваше значение абстрактно, возможно, оно нуждается в каком-то конкретном определении.

markspace 31.10.2022 23:35

Поскольку он абстрактен в суперклассе, вы не определили его достаточно, чтобы Котлин мог решить, есть ли this.sweetness или нет. (Например, это также может быть геттер.) Вы должны указать это в подтипе с помощью override.

Louis Wasserman 31.10.2022 23:53
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
Как вычислять биты и понимать побитовые операторы в Java - объяснение с примерами
В компьютерном программировании биты играют важнейшую роль в представлении и манипулировании данными на двоичном уровне. Побитовые операции...
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Поднятие тревоги для долго выполняющихся методов в Spring Boot
Приходилось ли вам сталкиваться с требованиями, в которых вас могли попросить поднять тревогу или выдать ошибку, когда метод Java занимает больше...
Полный курс Java для разработчиков веб-сайтов и приложений
Полный курс Java для разработчиков веб-сайтов и приложений
Получите сертификат Java Web и Application Developer, используя наш курс.
0
2
60
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

переопределение абстрактного свойства требует, чтобы вы переопределили его на верхнем уровне и где-то упомянули override val.

Это может произойти либо в первичном конструкторе, например.

class MatchaBobaLatte(override val sweetness: Int) : BobaTea() {
    // ...
}

или явно объявив значение переопределения, например

class MatchaBobaLatte : BobaTea {
    override val sweetness: Int

    constructor(sweetness: Int) : super() { // Not this()!
        this.sweetness = sweetness
    }
}

или нравится

class MatchaBobaLatte(sweetness: Int) : BobaTea() {
    // primary constructor parameters are available for instance
    // initializer code
    override val sweetness = sweetness * 2
}

Ошибка, которую вы видите, является результатом комбинации нескольких вещей. Вы пытаетесь делегировать первичному this() конструктору, которого не существует, но именно ему нужно установить все val значения. Ошибка также появляется, если вы сделаете

class Reassign {
    val sweetness: Int; // when no value here, then

    // primary ctor must init all vals or you get
    // "Property must be initialized or be abstract"
    constructor() {
        sweetness = 42;
    }

    // can't touch vals in here any more because it runs
    // after "this()"
    constructor(foo: Int) : this() {
        sweetness = foo; // Val cannot be reassigned
    }
}

Спасибо за подробное объяснение! Я вижу, я забыл значение this() vs super(). И определение переопределенного значения val вверху, а затем его инициализация в конструкторе — это то, что я пытался, но, должно быть, потерпел неудачу из-за делегирования this(). Спасибо!

kranberry 02.11.2022 06:43

Другие вопросы по теме