Class inheritance with the main constructor
I have a parent class like this:
interface ITask { }
open class Task(val targetServer: Server) : ITask { }
Then there is a child element that inherits from it and overrides the primary constructor like this:
data class FileTask(val sourceServer: Server, targetServer: Server) : Task(targetServer = targetServer) {
}
This throws a compile error in eclipse as
The primary constructor of a data class should only have property parameters (val / var)
Removing the keyword data
from the class header will throw an error, but I don't understand why.
Keeping the keyword data
and adding var
to targetServer
gives another error
'targetServer' hides member of supertype 'Task' and needs modification 'override'
Adding override
in targetServer
for override var targetServer: Server
raises another error
"targetServer" in "Task" is final and cannot be overridden
I need help to understand these errors.
source to share
The original error is that a data class cannot have parameters in its main constructor other than properties val
or var
. Removing the keyword data
removes this restriction.
It was mentioned that data classes usually do not work well with inheritance. It is assumed that they are used as simple data transfer objects and are not suitable for participating in hierarchies because it becomes difficult to understand what properties will be considered in the generated method implementations. It's best not to use them at all.
Read more about data classes and inheritance here - this is a proposal that was implemented in Kotlin 1.1.
To get back to the specific issue, if you really should make this class a data class, you can mark the property in the base class as open
and then override it in FileTask
, like:
open class Task(open val targetServer: Server) : ITask
data class FileTask(val sourceServer: Server, override val targetServer: Server): Task(targetServer = targetServer)
It basically hides the property declared in Task
and always accesses the property in FileTask
.
I don't know what your exact requirements are for your classes, but one thing you could do to clean it up and make it a little better is to do Task
its abstract property too targetServer
, for example
abstract class Task : ITask {
abstract val targetServer: Server
}
data class FileTask(val sourceServer: Server, override val targetServer: Server) : Task()
This way you won't have an unnecessary property (and backing field) in the base class, and you have to have a property targetServer
in all classes that inherit from Task
. You can also take it even further and put the property in an interface ITask
.
interface ITask {
val targetServer: Server
}
source to share
I know this is a very old post, but I was struggling with the same problem and doing a superclass abstraction was not a solution. You just need to do the following:
change this value
open class Task(val targetServer: Server) : ITask { }
to (Note that I made the targetServer variable open)
open class Task(open val targetServer: Server) : ITask { }
source to share