Inheritance 在Kotlin中扩展数据类
数据类似乎是Java中老式POJO的替代品。很可能这些类会允许继承,但我看不到扩展数据类的方便方法。我需要的是这样的东西:Inheritance 在Kotlin中扩展数据类,inheritance,kotlin,abstract,data-class,Inheritance,Kotlin,Abstract,Data Class,数据类似乎是Java中老式POJO的替代品。很可能这些类会允许继承,但我看不到扩展数据类的方便方法。我需要的是这样的东西: open data class Resource (var id: Long = 0, var location: String = "") data class Book (var isbn: String) : Resource() 由于component1()方法冲突,上述代码失败。只在其中一个类中保留数据注释也不起作用 也许还有另一种扩展数据类的习惯用法 UPD:
open data class Resource (var id: Long = 0, var location: String = "")
data class Book (var isbn: String) : Resource()
由于component1()
方法冲突,上述代码失败。只在其中一个类中保留数据
注释也不起作用
也许还有另一种扩展数据类的习惯用法
UPD:我可能只注释一个子类,但是数据注释只处理构造函数中声明的属性。也就是说,我必须声明所有父级的属性open
并覆盖它们,这很难看:
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()
事实是:数据类不能很好地处理继承。我们正在考虑禁止或严格限制数据类的继承。例如,众所周知,在非抽象类的层次结构中,无法正确实现equals()
所以,我所能提供的就是:不要对数据类使用继承。在构造函数之外的超类中将属性声明为抽象属性,并在子类中重写它们
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()
上述使用抽象类的解决方案实际上生成了相应的类,并让数据类从中扩展
如果您不喜欢抽象类,那么使用接口如何
Kotlin中的接口可以具有如下所示的属性
我很好奇Kotlin是如何编译的。下面是等效的Java代码(使用Intellij[Kotlin bytecode]功能生成):
如您所见,它的工作方式与普通数据类完全相同 您可以从非数据类继承数据类。不允许从另一个数据类继承数据类,因为在继承的情况下,无法使编译器生成的数据类方法一致直观地工作。@eljko Trogrlić的答案是正确的。但是我们必须重复与抽象类中相同的字段
此外,如果我们在抽象类中有抽象子类,那么在数据类中,我们不能从这些抽象子类扩展字段。我们应该首先创建数据子类,然后定义字段
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()
}
抽象类抽象类{
抽象val代码:Int
抽象值url:字符串?
抽象val错误:错误?
抽象类错误{
抽象val消息:列表?
}
}
数据类历史记录(
val数据:字符串?,
覆盖val代码:Int,
覆盖val url:字符串?,
//不要在这里扩展AbstractClass.Errors,但Kotlin允许这样做。
覆盖val错误:错误?
):AbstractClass(){
//在此扩展一个数据类,然后可以将其用于“errors”字段。
数据类错误(
覆盖val消息:列表?
):AbstractClass.Errors()
}
您可以从非数据类继承数据类
基类
open class BaseEntity (
@ColumnInfo(name = "name") var name: String? = null,
@ColumnInfo(name = "description") var description: String? = null,
// ...
)
儿童班
@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()
它起作用了。科特林的特质会有所帮助
interface IBase {
val prop:String
}
interface IDerived : IBase {
val derived_prop:String
}
数据类
data class Base(override val prop:String) : IBase
data class Derived(override val derived_prop:String,
private val base:IBase) : IDerived, IBase by base
样本使用
val b = Base("base")
val d = Derived("derived", b)
print(d.prop) //prints "base", accessing base class property
print(d.derived_prop) //prints "derived"
这种方法也可以作为@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
虽然在层次结构中正确地实现equals()
确实是一个难题,但支持继承其他方法还是不错的,例如:toString()
更具体地说,让我们假设我们有以下构造(显然,它不起作用,因为toString()
不是继承的,但是如果它可以继承,那不是很好吗?)
假设我们的User
和Location
实体返回其相应的资源ID(UserResourceId
和LocationResourceId
),调用toString()
在任何资源ID
上都可能产生一个非常好的小表示,通常对所有子类型都有效:/users/4587
,/locations/23
,等等。不幸的是,由于没有子类型继承到从抽象基资源ID
重写的toString()
方法,调用toString()
实际上会导致不太漂亮的表示:
,
还有其他方法可以对上述内容进行建模,但这些方法要么迫使我们使用非数据类(错过了数据类的许多好处),要么我们最终在所有数据类中复制/重复toString()
实现(无继承).我发现在DTO中使用继承的最佳方法是使用插件在java中创建数据类
不要忘记在注释中将lombok.equalsAndHashCode.callSuper设置为trueKotlin隐式创建返回第N个属性值的方法componentN()
。请参阅上的文档以打开属性,您还可以将资源抽象化或使用编译器插件。Kotlin对开/闭原则要求严格。@Dmitry因为我们无法扩展数据类,您保持父类变量打开并在子类中简单重写它们的“解决方案”是否可以解决这个问题?我认为这个问题没有太多解决方案。到目前为止,我的观点是,数据类不能有任何数据子类。如果我们有一个库代码,比如某个ORM,并且我们想要扩展它的模型以拥有我们的持久数据模型,该怎么办?@AndreyBreslav并不反映Kotlin 1.1之后的状态。自1.1版以来,数据类和继承是如何结合在一起的?@EugenPechanec看到了这个例子:如果我们不能对数据类使用继承,那就意味着在逻辑相同而数据不同的情况下会有大量重复的代码……由于缺乏继承支持,我复制了大量的代码,非常糟糕,这似乎是最灵活的。我真的非常希望我们可以让数据类彼此继承……您好,先生,感谢您以简洁的方式处理数据类继承。当我将抽象类用作泛型类型时,我面临一个问题。我得到一个类型的Mism
val b = Base("base")
val d = Derived("derived", b)
print(d.prop) //prints "base", accessing base class property
print(d.derived_prop) //prints "derived"
@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
abstract class ResourceId(open val basePath: BasePath, open val id: Id) {
// non of the subtypes inherit this... unfortunately...
override fun toString(): String = "/${basePath.value}/${id.value}"
}
data class UserResourceId(override val id: UserId) : ResourceId(UserBasePath, id)
data class LocationResourceId(override val id: LocationId) : ResourceId(LocationBasePath, id)