Повторяющиеся поля в классах данных, которые расширяют другие (запечатанные) классы?

Когда класс данных расширяет запечатанный класс, содержащий неабстрактное свойство 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 ответа

В таком случае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(),

Увидеть:

Почему поле в родительском классе не используется дочерним классом?

Зачем это? Вы определили свойство на основе поля field1 в обоих классах. Оба поля будут существовать, но getField1() метод переопределяется дочерним классом для возврата поля дочернего класса.

Есть ли способ изменить видимость поля в родительском классе на защищенный, чтобы он мог повторно использоваться дочерним классом?

Поля свойств lateinit имеют ту же видимость, что и геттеры. Но я не уверен, что ты этого хочешь.

Как насчет этого?

sealed class Foo {
    abstract val field1: String?
}

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

Смотрите обсуждение здесь: https://twitter.com/orangy/status/1033067930248867840

Другие вопросы по тегам