扩展其他(密封)类的数据类中的重复字段?

时间:2018-08-17 16:56:47

标签: kotlin data-class

当数据类扩展包含非抽象open val属性的密封类时,生成的子数据类将包含与父类的私有字段重复的私有字段。

sealed class Foo(open val field1: String? = null)

data class Bar(override val field1: String? = null) : Foo(field1)

javap -p Foo.class的输出:

public abstract class com.example.Foo {
    private final java.lang.String field1;
    public java.lang.String getField1();
    private com.example.Foo(java.lang.String);
    com.example.Foo(java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker);
    public com.example.Foo(java.lang.String, kotlin.jvm.internal.DefaultConstructorMarker);
}

还有javap -p Bar.class

public final class com.example.Bar extends com.example.Foo {
    private final java.lang.String field1;
    public java.lang.String getField1();
    public com.example.Bar(java.lang.String);
    public com.example.Bar(java.lang.String, int, kotlin.jvm.internal.DefaultConstructorMarker);
    public com.example.Bar();
    public final java.lang.String component1();
    public final com.example.Bar copy(java.lang.String);
    public static com.example.Bar copy$default(com.example.Bar, java.lang.String, int, java.lang.Object);
    public java.lang.String toString();
    public int hashCode();
    public boolean equals(java.lang.Object);
}

Bar.class的字节码包含其自己的私有字段field1;父类中的字段似乎没有被子类重复使用。

在使用通过反射设置字段的框架时,将设置哪个字段?为什么父类中的字段不能被子类重新使用?是否可以将父类中字段的可见性更改为protected,以便子类可以重复使用它?

3 个答案:

答案 0 :(得分:0)

该字段未被重用,因为您声明了一个单独的属性,该属性具有自己的后备字段。如果要重复使用该字段,请将代码更改为:

sealed class Foo(val field1: String? = null)

data class Bar(field1: String? = null) : Foo(field1)

答案 1 :(得分:0)

在这种情况下,Bar实际上将该字段保留了两次。具有单个字段的两种选择:

sealed class Foo(val field1: String?)
data class Bar(private val hiddenField1: String? = null) : Foo(hiddenField1)

sealed class Foo {
    abstract val field1: String?
}
data class Bar(override val field1: String? = null) : Foo()

答案 2 :(得分:0)

  

在使用通过反射设置字段的框架时,将设置哪个字段?

这取决于您使用的类。 Foo::class.java.getDeclaredField()Bar::class.java.getDeclaredField()

请参阅:

  

为什么父类中的字段不能被子类重新使用?

为什么要这么做?您在两个类中都定义了字段支持的属性field1。这两个字段都将存在,但是getField1()方法被子类覆盖以返回子类的字段。

  

是否可以将父类中字段的可见性更改为protected,以便子类可以重复使用?

lateinit属性的字段具有与getter相同的可见性。但是我不确定那不是您想要的。

怎么样?

sealed class Foo {
    abstract val field1: String?
}

data class Bar(override val field1: String? = null) : Foo()

请参见此处的讨论:https://twitter.com/orangy/status/1033067930248867840