example data classes inheritance kotlin data-class

inheritance - data - Ampliar clase de datos en Kotlin



kotlin data class setter (7)

Las clases de datos parecen ser el reemplazo de los POJO anticuados en Java. Es bastante esperable que estas clases permitan la herencia, pero no veo una manera conveniente de extender una clase de datos. Lo que necesito es algo como esto:

open data class Resource (var id: Long = 0, var location: String = "") data class Book (var isbn: String) : Resource()

El código anterior falla debido al choque de los métodos del component1() . Dejar data anotación de data en solo una de las clases tampoco funciona.

¿Quizás hay otro idioma para extender las clases de datos?

UPD: podría anotar solo la clase secundaria hijo, pero data anotación de data solo maneja las propiedades declaradas en el constructor. Es decir, tendría que declarar open todas las propiedades de los padres y anularlas, lo cual es feo:

open class Resource (open var id: Long = 0, open var location: String = "") data class Book ( override var id: Long = 0, override var location: String = "", var isbn: String ) : Resource()


Declare las propiedades en la superclase fuera del constructor como abstractas y anúlelas en la subclase.

abstract class Resource { abstract var id: Long abstract var location: String } data class Book ( override var id: Long = 0, override var location: String = "", var isbn: String ) : Resource()


La respuesta de @ Željko Trogrlić es correcta. Pero tenemos que repetir los mismos campos que en una clase abstracta.

Además, si tenemos subclases abstractas dentro de la clase abstracta, en una clase de datos no podemos extender los campos de estas subclases abstractas. Primero debemos crear una subclase de datos y luego definir campos.

abstract class AbstractClass { abstract val code: Int abstract val url: String? abstract val errors: Errors? abstract class Errors { abstract val messages: List<String>? } } data class History( val data: String?, override val code: Int, override val url: String?, // Do not extend from AbstractClass.Errors here, but Kotlin allows it. override val errors: Errors? ) : AbstractClass() { // Extend a data class here, then you can use it for ''errors'' field. data class Errors( override val messages: List<String>? ) : AbstractClass.Errors() }


La solución anterior que usa la clase abstracta en realidad genera la clase correspondiente y deja que la clase de datos se extienda desde ella.

Si no prefiere la clase abstracta, ¿qué tal usar una interfaz ?

La interfaz en Kotlin puede tener propiedades como se muestra en este artículo .

interface History { val date: LocalDateTime val name: String val value: Int } data class FixedHistory(override val date: LocalDateTime, override val name: String, override val value: Int, val fixedEvent: String) : History

Tenía curiosidad por cómo Kotlin compila esto. Aquí hay un código Java equivalente (generado utilizando la función Intellij [Kotlin bytecode]):

public interface History { @NotNull LocalDateTime getDate(); @NotNull String getName(); int getValue(); } public final class FixedHistory implements History { @NotNull private final LocalDateTime date; @NotNull private final String name; private int value; @NotNull private final String fixedEvent; // Boring getters/setters as usual.. // copy(), toString(), equals(), hashCode(), ... }

Como puede ver, ¡funciona exactamente como una clase de datos normal!


La verdad es que las clases de datos no juegan demasiado bien con la herencia. Estamos considerando prohibir o restringir severamente la herencia de las clases de datos. Por ejemplo, se sabe que no hay forma de implementar equals() correctamente en una jerarquía en clases no abstractas.

Entonces, todo lo que puedo ofrecer: no use la herencia con clases de datos.


Los rasgos de Kotlin pueden ayudar.

interface IBase { val prop:String } interface IDerived : IBase { val derived_prop:String }

clases de datos

data class Base(override val prop:String) : IBase data class Derived(override val derived_prop:String, private val base:IBase) : IDerived, IBase by base

uso de muestra

val b = Base("base") val d = Derived("derived", b) print(d.prop) //prints "base", accessing base class property print(d.derived_prop) //prints "derived"

Este enfoque también puede ser una solución para problemas de herencia con @Parcelize

@Parcelize data class Base(override val prop:Any) : IBase, Parcelable @Parcelize // works fine data class Derived(override val derived_prop:Any, private val base:IBase) : IBase by base, IDerived, Parcelable


Puede heredar una clase de datos de una clase que no sea de datos. No se permite heredar una clase de datos de otra clase de datos porque no hay forma de hacer que los métodos de clase de datos generados por el compilador funcionen de manera coherente e intuitiva en caso de herencia.


Puede heredar una clase de datos de una clase que no sea de datos.

Clase base

open class BaseEntity ( @ColumnInfo(name = "name") var name: String? = null, @ColumnInfo(name = "description") var description: String? = null, // ... )

clase infantil

@Entity(tableName = "items", indices = [Index(value = ["item_id"])]) data class CustomEntity( @PrimaryKey @ColumnInfo(name = "id") var id: Long? = null, @ColumnInfo(name = "item_id") var itemId: Long = 0, @ColumnInfo(name = "item_color") var color: Int? = null ) : BaseEntity()

Funcionó.