In this post I am going to look into Kotlin properties [1] from a Java developers perspective. By a few examples and by looking into the generated code.
I have created an example project on GitHub. You will find a few examples of how to declare properties - and for each of them, also identical unit tests in Java and Kotlin.
Let’s demystify those properties 🙂
Example: mutable and read-only properties
1
2
3
4
class First {
var messageOne: String? = "one"
val messageTwo = "two"
}
Keyword var
is what makes messageOne
mutable. It is also nullable (the question mark). Keyword val
is what makes messageTwo
read-only.
Running ./gradlew build javap
in the example project compiles the code, runs the Kotlin/Java tests and ends up with the following javap
dump:
1
2
3
4
5
6
7
8
9
10
11
public final class com.moelholm.First {
private java.lang.String messageOne;
private final java.lang.String messageTwo;
public final java.lang.String getMessageOne();
public final void setMessageOne(java.lang.String);
public final java.lang.String getMessageTwo();
public com.moelholm.First();
}
This is how it looks like from Java land.
The val
modifier in Kotlin is basically syntactic sugar for generating a final
field plus a getter method. So that’s how val
s become read-only.
The var
modifier in Kotlin ensures that we get a field plus a getter method and a setter method. So that’s how var
s become mutable.
The following two tests shows how we can use the properties from unit tests in Java…:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class FirstTests {
@Test
public void test() {
First first = new First();
first.setMessageOne("Hello from Java");
assertThat(first.getMessageOne()).isEqualTo("Hello from Java");
assertThat(first.getMessageTwo()).isEqualTo("two");
}
}
…as well as Kotlin:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
class FirstTests {
@Test
fun test() {
val first = First()
first.messageOne = "Hello from Kotlin"
assertThat(first.messageOne).isEqualTo("Hello from Kotlin")
assertThat(first.messageTwo).isEqualTo("two")
}
}
It is very visible from the Java unit test why you cannot update messageTwo
: there is simply no setter method.
Regarding nullability: You cannot see how that works by looking at the javap output above. But if you add a -v
flag to it, then you will see that the bytecode comes with the following Constant Pool declarations: Lorg/jetbrains/annotations/Nullable;
and Lorg/jetbrains/annotations/NotNull;
. The Kotlin compiler uses these to annotate members with the desired nullability behavior.
There is much more…
There is more to Kotlin properties than shown in this post.
For example Kotlin also has delegated properties and late initialized properties. And it is possible to provide custom getter/setter functionality in the property declaration as well.
Very interesting topics; subject for another post.