Reputation: 21
When a data class extends a sealed class containing a non-abstract open val property, the generated child data class contains private fields that duplicate the private fields of the parent class.
sealed class Foo(open val field1: String? = null)
data class Bar(override val field1: String? = null) : Foo(field1)
Output from 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);
}
And 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);
}
The bytecode for Bar.class
contains its own private field field1
; the field in the parent class does not appear to be re-used by the child class.
When using frameworks that set fields using reflection, which field will be set? Why is the field in the parent class not re-used by the child class? Is there a way to change the visibility of the field in the parent class to protected
so it can be re-used by the child class?
Upvotes: 2
Views: 1499
Reputation: 38223
When using frameworks that set fields using reflection, which field will be set?
It depends on the class you use. Foo::class.java.getDeclaredField()
or Bar::class.java.getDeclaredField()
.
See:
Why is the field in the parent class not re-used by the child class?
Why should it? You defined a field-backed property field1
in both classes. Both fields will exist but getField1()
method is overridden by child class to return child class' field.
Is there a way to change the visibility of the field in the parent class to protected so it can be re-used by the child class?
Fields of lateinit properties have the same visibility as the getters. But I'm not sure that's what you want.
How about this?
sealed class Foo {
abstract val field1: String?
}
data class Bar(override val field1: String? = null) : Foo()
See discussion here: https://twitter.com/orangy/status/1033067930248867840
Upvotes: 0
Reputation: 21799
In that caseBar
holds the field indeed twice. Two alternatives to have a single field:
sealed class Foo(val field1: String?)
data class Bar(private val hiddenField1: String? = null) : Foo(hiddenField1)
or
sealed class Foo {
abstract val field1: String?
}
data class Bar(override val field1: String? = null) : Foo()
Upvotes: 2
Reputation: 97123
The field is not reused because you declared a separate property, which has its own backing field. If you want to reuse the field, change your code to:
sealed class Foo(val field1: String? = null)
data class Bar(field1: String? = null) : Foo(field1)
Upvotes: 0