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



当数据类扩展包含非抽象 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以便子类可以重用它?

在这种情况下,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()

该字段不会重用,因为您声明了一个单独的属性,该属性具有自己的支持字段。如果要重用该字段,请将代码更改为:

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

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

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

看:

  • https://programming.guide/java/accessing-private-fields-of-superclass-through-reflection.html
  • Java反射中的getFields和getDeclaredFields有什么区别

为什么子类不重用父类中的字段?

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

有没有办法将父类中字段的可见性更改为受保护,以便子类可以重用它?

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

怎么样?

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

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

最新更新