1

在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 的最佳方式?

4

1 回答 1

2

IntelliJ Idea 将您的 Java 代码翻译成以下内容,这在样板中似乎是合理的并且减少了。所以,我会回答,“不,你的前提不能准确地描述 Kotlin 是否是最先进的”。

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
        }
    }
}

但是,您的问题专门针对“数据”类。数据类是语言的一个很好的组件,它为我们提供了“解构”和一些有用的自动生成的解构方法(例如componentN)。因此,使用上面的代码(并添加open到 class 和 and 的声明ab,您的示例派生类的实现略有不同。

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)
        }
    }
}

这似乎是合理的,因为您的起始示例不是数据类,而您显然希望使用 Kotlin 数据类。它为您提供了一个理想的功能(如果您需要它),但代价是更多的代码冗长。

如果将基类声明为sealedandabas ,则派生类是相同的代码abstract

因此,对于数据类,您希望在派生类中作为“数据”公开的基类的任何部分都存在重复(它已经公开,只是不作为“数据类”特殊成员,如图所示下面的例子)。但这类似于其他情况下的覆盖。只是想一想,现在考虑以下派生类。

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
        }
    }
}

你得到基类的所有成员,以及派生类的新数据成员。但是,如果您想要覆盖的好处,它又会花费一些句法语言(对于派生数据类和常规类)。

最后一点。数据类仍然有其他与继承和覆盖相关的奇怪之处,可能仍然需要解决。 toStringhashCodeequals获得他们自己的特殊实现,并且文档说......

如果数据类体中有equals()、hashCode()或toString()的显式实现或超类中的最终实现,则不生成这些函数,使用现有实现;

...我发现阅读起来令人困惑(导致我进行实验而不是依赖文档)。还有其他一些关于toString数据类的斗争的问题(例如:这个 OP 试图创建一个 DTO)。

所以,我认为这是最先进的,而且还不错(IMO)。是的,如果你想要数据类的特性,你可以像你所做的那样翻译它。

于 2017-09-12T20:00:45.413 回答