如何对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 以及 ab 的声明),这里是您的示例派生的稍微不同的实现 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,将 ab 声明为 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 仍然有其他与继承和覆盖相关的怪异问题,这些问题可能仍需解决。 toStringhashCodeequals 有自己的特殊实现,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 的特性,你可以像你所做的那样翻译它。