数据类似乎是Java中老式pojo的替代品。这些类允许继承是可以预料的,但我看不出扩展数据类的方便方法。我需要的是这样的东西:
open data class Resource (var id: Long = 0, var location: String = "")
data class Book (var isbn: String) : Resource()
上面的代码失败是因为component1()方法的冲突。只在一个类中留下数据注释也不能完成这项工作。
也许还有另一种扩展数据类的习惯用法?
UPD:我可能只注释子子类,但数据注释只处理构造函数中声明的属性。也就是说,我必须声明所有的父属性是开放的,并重写它们,这是丑陋的:
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()
上述方案使用抽象类实际生成相应的类,并让数据类从它扩展。
如果您不喜欢抽象类,那么使用接口如何?
Kotlin中的接口可以具有本文所示的属性。
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
我很好奇Kotlin是如何编译的。下面是等价的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(), ...
}
正如您所看到的,它的工作方式完全像一个普通的数据类!
虽然在层次结构中正确地实现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)
Assuming our User and Location entities return their appropriate resource IDs (UserResourceId and LocationResourceId respectively), calling toString() on any ResourceId could result in quite a nice little representation that is generally valid for all subtypes: /users/4587, /locations/23, etc. Unfortunately, because non of the subtypes inherited to overridden toString() method from the abstract base ResourceId, calling toString() actually results in a less pretty representation: <UserResourceId(id=UserId(value=4587))>, <LocationResourceId(id=LocationId(value=23))>
还有其他方法可以对上述模型进行建模,但这些方法要么迫使我们使用非数据类(错过了数据类的许多好处),要么我们最终在所有数据类中复制/重复toString()实现(没有继承)。
@Željko trogrliic的答案是正确的。但是我们必须像在抽象类中一样重复相同的字段。
同样,如果我们在抽象类中有抽象子类,那么在数据类中我们不能从这些抽象子类扩展字段。我们应该首先创建数据子类,然后定义字段。
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()
}
上述方案使用抽象类实际生成相应的类,并让数据类从它扩展。
如果您不喜欢抽象类,那么使用接口如何?
Kotlin中的接口可以具有本文所示的属性。
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
我很好奇Kotlin是如何编译的。下面是等价的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(), ...
}
正如您所看到的,它的工作方式完全像一个普通的数据类!