Home > Blockchain >  Kotlin Inheritance - Overriding properties
Kotlin Inheritance - Overriding properties

Time:02-11

So I started learning Kotlin today and got to Classes when I noticed something weird. When I run this code:

fun main() {
    val dog_1 = Dog("Walrek", 7)
}

open class Animal(
    open val type: String,
    open val name: String,
    open val speed: Int,
) {
    init {
        println("(Ani init) New animal: $type called $name with $speed speed")
    }
}

class Dog(
    override val name: String,
    override val speed: Int,
): Animal("Dog", name, speed) {}

The init method will print out: (Ani init) New animal: Dog called null with 0 speed.

At first I thought I messed up somewhere and somehow I'm not passing the arguments properly into the Animal class, but then I added these two lines of code:

init {
    println("(Dog init) New animal: $type called $name with $speed speed")
}

into Dog class, and

println(dog_1.name)

in the main function, and got this as an output:

(Ani init) New animal: Dog called null with 0 speed
(Dog init) New animal: Dog called Walrek with 7 speed
Walrek

So now my question is, why weren't the parameters passed into the Animal class, and yet I can access them as usual after creating the Dog instance?

CodePudding user response:

You should be getting a compiler warning. You should never use open properties or functions at construction time (in init blocks or property declarations), because it causes this kind of unwanted behavior. It's just about the only way you can get a NullPointerException in Kotlin without using !!.

The reason it happens is that the superclass's constructor (which includes init blocks and property declarations) is run before the subclass. Since you override the property name in the subclass, the backing field of the property name has not yet been initialized by the time init of the superclass is called, so the property returns the default Java field value of null. In the case of speed, the field type is a Java primitive int so its default value is 0.

Note that in your specific example, there was no need to override these properties because you are passing these values to the superconstructor anyway. You could remove the open keyword before the properties and declare your Dog like:

class Dog(
    name: String,
    speed: Int,
): Animal("Dog", name, speed) {}

Then it will behave properly.

  • Related