Tomasz
Tomasz

Reputation: 121

What are the differences between Kotlin class properties and Java class fields

I've started to learn Kotlin. My current background is Java. I found out that class properties in Kotlin are quite different from class fields in Java, even though they look similar. In his question I would like to gather together all technical differences between those two. This is what I’ve already figured out:

Java field and hiding vs Kotli properties and overriding
(and actually this pushed me to write this post):

In Java, a field of a base class is hidden by a field with the same name in derived class, so which field is used depends on the type of a reference to the object which contains the field, not the type of the object itself (fields are not overridden like methods are, so they don't depend on runtime type of an object). For example this code:

class A {
    public String name = "A";
    public void printMessage() {
        System.out.println("Field accessed in method declared inside class A invoked form an object of " + getClass() + " : " + name);
    }
}

class B extends A{
    public String name = "B";
}

public class Main {
    public static void main(String... args){
        B b = new B();
        System.out.println("Field from instance of class B pointed by reference to B : " + b.name);
        A a = b;
        System.out.println("Field from instance of class B pointed by reference to A : "+a.name);
        a.printMessage();
    }
}

prints this :

Field from instance of class B pointed by reference to B : B
Field from instance of class B pointed by reference to A : A
Field accessed in method declared inside class A invoked form an object of class B : A

In contrast Kotlin properties are fields accessed by automatically generated getters and setters. Properties are overridden (not hidden), so property access is resolved at runtime, and the code with similar meaning as above written in Kotlin:

open class A {
    open val name = "A"
    fun printMessage() {
        println("Field accessed in method declared inside class A invoked form an object of $javaClass : $name")
    }
}

class B(override val name : String = "B") : A()

fun main(args : Array<String>) {
    val b : B = B()
    println("Field from instance of class B pointed by reference to B : " + b.name)
    val a : A = b;
    println("Field from instance of class B pointed by reference to A : " + a.name)
    a.printMessage()
}

prints this :

Field from instance of class B pointed by reference to B : B 
Field from instance of class B pointed by reference to A : B 
Field accessed in method declared inside class A invoked form an object of class B : B

Access level
Java fields are package – private by default. Kotlin properties are public by default.

Default initialization
Java fields are initialized with reasonable default values (as describet here : https://docs.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html).

Every Kotlin class property has to be created in a way which will allow it to provide explicitly given value when it will be accessed. One can achieve this by initiallizer, constructor, setter, lazy initialization:

class InitValues(val inCtor : String = "Given in constructor"){
    var byInitializer = "In initializer"
    var initializedWithNull : String? = null
    val valueGivenByGetter
        get() : String {
            return "This value is given by getter"
        }
    val byLazyInit : String by lazy { "This is lazy init" }
}

but value which should be returned has to be given – no defaults will be provided.

Are there any other technical differences regarding class fields / properties which may surprise Java programmer writing code in Kotlin?

(I’m not talking about additional features like for example delegated properties but those things which at first glance are similar to what exists in Java and can be delusive)

Upvotes: 11

Views: 3315

Answers (1)

Yogesh Umesh Vaity
Yogesh Umesh Vaity

Reputation: 48149

I would like to elaborate more on the differences between a Java field and a Kotlin Property. Have a look at the following examples of Java field and Kotlin property.

Examples

Java field:

class Product {
    public int discount = 20;
}

Kotlin property:

class Product { 
    var discount: Int = 20
}

Auto-generated Accessors

The two examples above are not equivalent. Because in Kotlin, getters and setters are auto-generated for the properties. The Kotlin property above is equivalent to the following Java code:

class Product {
    private int discount = 20;

    public int getDiscount() {
        return discount;
    }

    public void setDiscount(int discount) {
        this.discount = discount;
    }
}

So the difference between the Java field and Kotlin Property is that the Kotlin property creates a field and its accessors. When the property is a val, it creates a getter only. When the property is a var, it creates both a getter and a setter. And the field becomes private by default as shown in the above code, the discount is private. But you can access the discount using its getters and setters.


Custom Accessors

What if we want to implement some logic or validation inside the getters and setters in Kotlin? For example, when someone is setting the discount on the product, we want to make sure it's never above 85%. In this case, we can define the custom accessors for the discount property like following:

class Product {
    var discount: Int = 20
        set(value) {
            if (value >= 85) {
                field = 85
            } else {
                field = value
            }
        }
}

The field is a reserved keyword in Kotlin which holds the value as a backing field. The above code result in:

product.discount = 70;
println(product.discount) // 70
product.discount = 90;
println(product.discount) // 85

We can do similar things with the getter using the get() method.


That's it! Hope that helps.

Upvotes: 16

Related Questions