数据类似乎是Java中老式POJO的替代品。很可能这些类允许继承,但我看不到扩展数据类的便捷方法。我需要的是这样的事情:
open data class Resource (var id: Long = 0, var location: String = "")
data class Book (var isbn: String) : Resource()
由于component1()
方法的冲突,上面的代码失败了。只在一个类中留下data
注释也不起作用。
也许还有另一个成语来扩展数据类?
UPD:我可能只注释子子类,但data
注释只处理构造函数中声明的属性。也就是说,我必须声明所有父级的属性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()
答案 0 :(得分:95)
事实是:数据类在继承方面不能很好地发挥作用。我们正在考虑禁止或严格限制数据类的继承。例如,它已知无法在非抽象类的层次结构中正确实现equals()
。
所以,我可以提供:不要在数据类中使用继承。
答案 1 :(得分:73)
将构造函数之外的超类中的属性声明为abstract,并在子类中覆盖它们。
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()
答案 2 :(得分:16)
使用抽象类的上述解决方案实际上会生成相应的类,并让数据类从其扩展。
如果您不喜欢抽象类,如何使用界面?
Kotlin中的接口可以具有属性,如本this article所示。.
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
我很好奇科特林是如何编译的。这是等效的Java代码(使用Intellij [Kotlin字节码]功能生成):
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(), ...
}
如您所见,它的工作原理与普通数据类完全一样!
答案 3 :(得分:2)
@ŽeljkoTrogrlić的答案是正确的。但是我们必须重复与抽象类相同的字段。
如果抽象类内部有抽象子类,那么在数据类中,我们将无法扩展这些抽象子类的字段。我们应该首先创建 data子类,然后定义字段。
<script src="https://code.jquery.com/jquery-2.0.3.min.js"></script>
<script src="https://unpkg.com/cytoscape@3.1.0/dist/cytoscape.min.js"></script>
<!-- for testing with local version of cytoscape.js -->
<!--<script src="../cytoscape.js/build/cytoscape.js"></script>-->
<script src="https://unpkg.com/cytoscape-cose-bilkent@4.0.0/cytoscape-cose-bilkent.js"></script>
<script src="https://unpkg.com/cytoscape-expand-collapse@3.1.1/cytoscape-expand-collapse.js"></script>
<div id="cy"></div>
答案 4 :(得分:1)
您可以从非数据类继承数据类。不允许从另一个数据类继承数据类,因为在继承的情况下,无法使编译器生成的数据类方法一致且直观地工作。
答案 5 :(得分:1)
虽然在层次结构中正确实现equals()
确实是一个麻烦,但支持继承其他方法(例如:toString()
)仍然很不错。
更具体一点,让我们假设我们具有以下构造(显然,它不起作用,因为toString()
没有被继承,但是如果可以,那会不会很好?):>
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)
假设我们的User
和Location
实体返回其相应的资源ID(分别为UserResourceId
和LocationResourceId
),并在任意toString()
上调用ResourceId
可能会产生一个很好的小表示形式,该表示形式通常对所有子类型有效:/users/4587
,/locations/23
等。不幸的是,因为没有一个子类型继承了抽象基础的toString()
方法ResourceId
,调用toString()
实际上会产生不太漂亮的表示形式:<UserResourceId(id=UserId(value=4587))>
,<LocationResourceId(id=LocationId(value=23))>
还有其他方法可以对上述模型进行建模,但是这些方法要么迫使我们使用非数据类(错过了数据类的许多好处),要么最终我们复制/重复了{{1 }}在我们所有数据类中的实现(无继承)。
答案 6 :(得分:0)
您可以从非数据类继承数据类。
基类
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()
有效。
答案 7 :(得分:0)
科特琳特质可以提供帮助。
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
答案 8 :(得分:0)
我发现在 DTO 中选择使用继承的最佳方法是使用 Lombok 插件在 Java 中创建数据类。
不要忘记在注释中将 lombok.equalsAndHashCode.callSuper 设置为 true
答案 9 :(得分:0)
data class User(val id:Long, var name: String)
fun main() {
val user1 = User(id:1,name:"Kart")
val name = user1.name
println(name)
user1.name = "Michel"
val user2 = User(id:1,name:"Michel")
println(user1 == user2)
println(user1)
val updateUser = user1.copy(name = "DK DK")
println(updateUser)
println(updateUser.component1())
println(updateUser.component2())
val (id,name) = updateUser
println("$id,$name") }