Наследование класса с помощью основного конструктора

У меня есть родительский класс следующим образом:

interface ITask { } open class Task(val targetServer: Server) : ITask { } 

Тогда там ребенок наследует его и переопределяет основной конструктор следующим образом:

 data class FileTask(val sourceServer: Server, targetServer: Server) : Task(targetServer = targetServer) { } 

Это бросает ошибку компиляции в eclipse как

Первичный конструктор класса данных должен иметь только параметры свойства (val / var)

Удаление ключевого слова data из заголовка класса приведет к ошибке, но я не понимаю, почему.

Сохранение ключевого слова data и добавление var к targetServer дает еще одну ошибку

«targetServer» скрывает член супертипа «Задача» и нуждается в модификации «переопределить»

Добавление override к targetServer для override var targetServer: Server выдает еще одну ошибку

«targetServer» в «Задаче» является окончательным и не может быть переопределен

Мне нужна помощь, чтобы понять эти ошибки.

Исходная ошибка заключается в том, что класс данных не может иметь параметры в своем основном конструкторе, кроме свойств val или var . Удаление ключевого слова data отменяет это ограничение.

Было упомянуто, что классы данных обычно не хорошо работают с наследованием. Предполагается, что они используются как простые объекты передачи данных и не подходят для участия в иерархиях, потому что становится трудно понять, какие свойства будут рассмотрены в реализациях сгенерированных методов. Лучше всего не использовать их здесь.

Для получения дополнительной информации о классах данных и наследовании, вот предложение, которое было реализовано в Kotlin 1.1.


Чтобы вернуться к конкретной проблеме, если вам действительно нужно сделать этот класс классом данных, вы можете пометить свойство в базовом классе как open а затем переопределить его в FileTask , например:

 open class Task(open val targetServer: Server) : ITask data class FileTask(val sourceServer: Server, override val targetServer: Server): Task(targetServer = targetServer) 

Это в основном скрывает свойство, объявленное в Task , и всегда обращается к свойству в FileTask .

Я не знаю, каковы ваши точные требования к вашим классам, но одна вещь, которую вы могли бы сделать, чтобы очистить ее и сделать ее немного лучше, – это сделать Task и ее свойство targetServer абстрактным:

 abstract class Task : ITask { abstract val targetServer: Server } data class FileTask(val sourceServer: Server, override val targetServer: Server) : Task() 

Таким образом, у вас не будет ненужного свойства (и поля поддержки) в базовом классе, и вы будете вынуждены иметь свойство targetServer во всех классах, которые наследуют от Task . Вы также можете сделать это еще дальше и поместить свойство в интерфейс ITask .

 interface ITask { val targetServer: Server }