如何对data-class使用简单继承?
How to use simple inheritance for data-class?
在java、
abstract class NumericValue{
private String a;
private String b;
public String getA() { return a; }
public void setA(String a) { this.a = a; }
public String getB() { return b; }
public void setB(String b) { this.b = b; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NumericValue that = (NumericValue) o;
if (a != null ? !a.equals(that.a) : that.a != null) return false;
return b != null ? b.equals(that.b) : that.b == null;
}
@Override
public int hashCode() {
int result = a != null ? a.hashCode() : 0;
result = 31 * result + (b != null ? b.hashCode() : 0);
return result;
}
}
class Abc extends NumericValue{
public static void main(String[] args) {
Abc abc = new Abc();
abc.getA();
}
}
在 Kotlin 中,这归结为:
方法一:
sealed class NumericValueA{
abstract var a: String
abstract var b: String
}
data class AbcA(
override var a:String,
override var b:String
):NumericValueA()
方法二:
open class NumericValueB(
open var a:String,
open var b:String
)
data class AbcB(
override var a:String,
override var b:String
):NumericValueB(a,b)
当您拥有仅继承属性的数据 类 时,这两种方法都倾向于大量重复,因为您必须再次写下您指定的所有内容 - 这根本无法扩展并且不知何故感觉不对。
这是最先进的还是真的是将以前的 java 代码转换为 kotlin 的最佳方法?
IntelliJ Idea 将您的 Java 代码翻译成以下内容,这看起来合理且减少了样板。所以,我会回答,"No, your premise does not accurately characterize whether or not Kotlin is state of the art "。
internal abstract class NumericValue {
var a: String? = null
var b: String? = null
override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val that = o as NumericValue?
if (if (a != null) a != that!!.a else that!!.a != null) return false
return if (b != null) b == that.b else that.b == null
}
override fun hashCode(): Int {
var result = if (a != null) a!!.hashCode() else 0
result = 31 * result + if (b != null) b!!.hashCode() else 0
return result
}
}
internal class Abc : NumericValue() {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val abc = Abc()
abc.a
}
}
}
但是,您的问题专门针对 "data" classes。数据 classes 是语言的一个很好的组成部分,它为我们提供了 "deconstruction" 和一些有用的自动生成的解构方法(例如 componentN
)。因此,使用上面的代码(并将 open
添加到 class 以及 a
和 b
的声明),这里是您的示例派生的稍微不同的实现 class.
internal data class AbcB (override var a: String?, override var b: String?) : NumericValue() {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val abc = AbcB("a","b")
println("b = " + abc.component2())
val n: NumericValue = abc
println("a = " + n.a)
}
}
}
这似乎是合理的,因为您的起始示例不是数据 class 并且您显然希望使用 Kotlin 数据 class。它为您提供了一个理想的功能(如果您需要的话),但代价是多了一点代码语言。
如果将基数声明为 sealed
,将 a
和 b
声明为 abstract
,则派生的 class 是相同的代码。
因此,在数据 classes 的情况下, 是 您想要公开为 "data" 在派生的 class 中(它已经公开,只是不作为 "data class" 特殊成员,如下例所示)。但这类似于其他上下文中的覆盖。仅供思考,现在考虑以下导出的 class.
internal data class AbcCD (var c: String?, var d: String?) : NumericValue() {
companion object {
@JvmStatic
fun x() {
val abc = AbcCD("c","d")
abc.b = "B"
abc.a = "A"
println("d = " + abc.component2())
abc.a
}
}
}
您获得基 class 的所有成员,以及派生 class 的新数据成员。但是如果你想要覆盖好处,它又会花费一些语法用语(对于派生数据 classes 和常规 classes)。
最后一点。数据 classes 仍然有其他与继承和覆盖相关的怪异问题,这些问题可能仍需解决。 toString
、hashCode
和 equals
有自己的特殊实现,documentation 说...
If there are explicit implementations of equals(), hashCode() or toString() in the data class body or final implementations in a superclass, then these functions are not generated, and the existing implementations are used;
... 我发现它读起来很混乱(导致我进行实验而不是依赖文档)。还有其他 SO 问题处理 toString
和数据 classes 的斗争(例如:this OP trying to create a DTO)。
所以,我认为这是最先进的,而且还不错(IMO)。是的,如果你想要数据 classes 的特性,你可以像你所做的那样翻译它。
在java、
abstract class NumericValue{
private String a;
private String b;
public String getA() { return a; }
public void setA(String a) { this.a = a; }
public String getB() { return b; }
public void setB(String b) { this.b = b; }
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
NumericValue that = (NumericValue) o;
if (a != null ? !a.equals(that.a) : that.a != null) return false;
return b != null ? b.equals(that.b) : that.b == null;
}
@Override
public int hashCode() {
int result = a != null ? a.hashCode() : 0;
result = 31 * result + (b != null ? b.hashCode() : 0);
return result;
}
}
class Abc extends NumericValue{
public static void main(String[] args) {
Abc abc = new Abc();
abc.getA();
}
}
在 Kotlin 中,这归结为:
方法一:
sealed class NumericValueA{
abstract var a: String
abstract var b: String
}
data class AbcA(
override var a:String,
override var b:String
):NumericValueA()
方法二:
open class NumericValueB(
open var a:String,
open var b:String
)
data class AbcB(
override var a:String,
override var b:String
):NumericValueB(a,b)
当您拥有仅继承属性的数据 类 时,这两种方法都倾向于大量重复,因为您必须再次写下您指定的所有内容 - 这根本无法扩展并且不知何故感觉不对。
这是最先进的还是真的是将以前的 java 代码转换为 kotlin 的最佳方法?
IntelliJ Idea 将您的 Java 代码翻译成以下内容,这看起来合理且减少了样板。所以,我会回答,"No, your premise does not accurately characterize whether or not Kotlin is state of the art "。
internal abstract class NumericValue {
var a: String? = null
var b: String? = null
override fun equals(o: Any?): Boolean {
if (this === o) return true
if (o == null || javaClass != o.javaClass) return false
val that = o as NumericValue?
if (if (a != null) a != that!!.a else that!!.a != null) return false
return if (b != null) b == that.b else that.b == null
}
override fun hashCode(): Int {
var result = if (a != null) a!!.hashCode() else 0
result = 31 * result + if (b != null) b!!.hashCode() else 0
return result
}
}
internal class Abc : NumericValue() {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val abc = Abc()
abc.a
}
}
}
但是,您的问题专门针对 "data" classes。数据 classes 是语言的一个很好的组成部分,它为我们提供了 "deconstruction" 和一些有用的自动生成的解构方法(例如 componentN
)。因此,使用上面的代码(并将 open
添加到 class 以及 a
和 b
的声明),这里是您的示例派生的稍微不同的实现 class.
internal data class AbcB (override var a: String?, override var b: String?) : NumericValue() {
companion object {
@JvmStatic
fun main(args: Array<String>) {
val abc = AbcB("a","b")
println("b = " + abc.component2())
val n: NumericValue = abc
println("a = " + n.a)
}
}
}
这似乎是合理的,因为您的起始示例不是数据 class 并且您显然希望使用 Kotlin 数据 class。它为您提供了一个理想的功能(如果您需要的话),但代价是多了一点代码语言。
如果将基数声明为 sealed
,将 a
和 b
声明为 abstract
,则派生的 class 是相同的代码。
因此,在数据 classes 的情况下, 是 您想要公开为 "data" 在派生的 class 中(它已经公开,只是不作为 "data class" 特殊成员,如下例所示)。但这类似于其他上下文中的覆盖。仅供思考,现在考虑以下导出的 class.
internal data class AbcCD (var c: String?, var d: String?) : NumericValue() {
companion object {
@JvmStatic
fun x() {
val abc = AbcCD("c","d")
abc.b = "B"
abc.a = "A"
println("d = " + abc.component2())
abc.a
}
}
}
您获得基 class 的所有成员,以及派生 class 的新数据成员。但是如果你想要覆盖好处,它又会花费一些语法用语(对于派生数据 classes 和常规 classes)。
最后一点。数据 classes 仍然有其他与继承和覆盖相关的怪异问题,这些问题可能仍需解决。 toString
、hashCode
和 equals
有自己的特殊实现,documentation 说...
If there are explicit implementations of equals(), hashCode() or toString() in the data class body or final implementations in a superclass, then these functions are not generated, and the existing implementations are used;
... 我发现它读起来很混乱(导致我进行实验而不是依赖文档)。还有其他 SO 问题处理 toString
和数据 classes 的斗争(例如:this OP trying to create a DTO)。
所以,我认为这是最先进的,而且还不错(IMO)。是的,如果你想要数据 classes 的特性,你可以像你所做的那样翻译它。