5

I'm trying to pass value to constructor and print the values.

open class Car(c: Int){ open var cost: Int = c init { println("This comes First $cost") } } open class Vehicle(cc: Int) : Car(cc) { override var cost: Int = 20000 init { println("This comes Second $cost") } fun show(){ println("cost = $cost") } } fun main() { var vehicle = Vehicle(1000) vehicle.show() } 

Output

This comes First 0 This comes Second 20000 cost = 20000 

if i just comment this line override var cost: Int = 20000

output would be

This comes First 1000 This comes Second 1000 cost = 1000 
  • Why super constructor cost is zero when override the property in subclass?
  • I need this to be compared to java concept for better explanation here
2
  • @Tenfour04 Intresting, but can you elaborate your answer. I'm not finding any resource for this. So, kindly give the answer with little more explanation in detail and ofcourse in simple words. Commented Apr 9, 2020 at 12:37
  • I fixed code formatting. When declaring the type of a variable we don't need to add a space, it should be cost: Int instead of cost : Int. Commented Apr 10, 2020 at 11:17

4 Answers 4

9

In Java to create a mutable property cost, you need to define a field cost and a getter and setter:

public class Car { private int cost; public Car(int c) { this.cost = c; System.out.println("This comes First " + getCost()); } public int getCost() { return cost; } public void setCost(int cost) { this.cost = cost; } } 

Kotlin has the concept of a property embedded in the language, so you can achieve the same with only creating a var property as you did:

open class Car(c : Int){ open var cost : Int = c init { println("This comes First $cost") } } 

This is much more concise from the developer perspective, but the implementation is the same. Kotlin compiler is generating a field cost, a get method and set method for us under the hood. Now the interesting part. When you make the cost property in the parent class open and overrides it in the child class, you are actually overriding the get method. It is not possible to override a field, neither in Kotlin nor Java.

As @Pawel mentioned in his answer that's the java code for the Vehicle child class:

public class Vehicle extends Car { private int cost = 20000; @Override public int getCost() { return this.cost; } @Override public void setCost(int var1) { this.cost = var1; } public final void show() { System.out.println("cost = " + getCost()); } public Vehicle(int cc) { super(cc); System.out.println("This comes Second " + getCost()); } } 

When you execute println("This comes First $cost") in the parent class, you are actually executing System.out.println("This comes First " + getCost()); and the actual getCost() being called is the one in the child class Vehicle. As the child class cost field has not been initialized yet, as we are still executing the super(cc) call, its value is zero.

Sign up to request clarification or add additional context in comments.

5 Comments

r u saying, init will run first then property will get initialized.
init is equivalent to this public Car(int c) { this.cost = c; System.out.println("This comes First " + getCost()); }. Property in Car class is initialized first, but the getCost() actually called in the System.out.println line is the one in the Vehicle class.
In week 4 of the course "Kotlin for Java Developers" on Coursera there is a video called "Constructors, Inheritance syntax" where this behavior is explained in detail.
Yes, it always looks for override methods and property. Someone answered the flow of execution below in steps. i understood now.
This is why it's recommended that constructors should never call any of their own methods that could be overridden. (And the property getter is such a method.)
8

Have you looked at generated bytecode and tried to reverse decompile it back to java? If you're confused how Kotlin works under the hood often times it can help you understand.

In this case your classes in Java would look like this (i decompiled your code and cleaned it up a little):

public class Car { private int cost; public int getCost() { return this.cost; } public void setCost(int var1) { this.cost = var1; } public Car(int c) { this.cost = c; System.out.println("This comes First " + getCost()); } } public class Vehicle extends Car { private int cost = 20000; public int getCost() { return this.cost; } public void setCost(int var1) { this.cost = var1; } public final void show() { System.out.println("cost = " + getCost()); } public Vehicle(int cc) { super(cc); System.out.println("This comes Second " + getCost()); } } 

What's happening is open var is just declaration for setter and getter which Vehicle overrides.

Remember that initialization of super class always happen before child, so when Car constructor is executed Vehicle is still not initialized (Vehicle.cost is still 0).

That means in first case:

This comes First 0 // Car constructor prints 0 because it returns Vehicle.cost which is unitialized This comes Second 20000 // Vehicle constructor returns initialized value cost = 20000 

And in second case where you DON'T override the cost, both Car and Vehicle return Car.cost:

This comes First 1000 // Car constructor assigns constructor parameter to Car.cost and returns it This comes Second 1000 // Vehicle constructor returns Car.cost as well cost = 1000 

Also note that in first case your constructor parameter is meaningless: it gets assigned to Car.cost but that field is inaccessible because it's shadowed by Vehicle.cost.

1 Comment

I didn't get you, i think you need to elaborate little more. why because, if i comment just override var cost : Int = 20000 the answer is completely as i expected. but not when uncomment. So I need more clarification on this
5

This behavior may not be intuitive, but it's the result of how properties work with the JVM.

When you subclass Car, the Car initialization occurs before the subclass Vehicle initialization. So the println call in Car's init block accesses the property before Vehicle is initialized. Since this access amounts to calling a getter method in Java, it is accessing the subclass's getter, not its own since it's been overridden. Since the subclass has not initialized yet at this stage, its getter returns the default value of the backing field, 0.

If you do this with a non-primitive, non-nullable property, you can "trick" Kotlin into giving you a Java NullPointerException for what can normally be assumed to be non-null.

In either case, the default code inspections should warn you about trying to access an open property during initialization, because of this unexpected kind of behavior.

The work-around would be to use a private backing property:

open class Car(c : Int){ private var _cost: Int = c open var cost : Int get() = _cost set(value) { _cost = value } init { println("This comes First $_cost") } } 

Comments

1

In simple words.

when object is created Vehicle(1000)
- first init will get called - then variables get initialized

step 1:- it will try to call constructor of Vehicle
step 2:- since it inherited Car it will try to call constructor of Car first
step 3:- it always look for override methods not overridden methods or properties So, $cost is pointing to override property.
step 4:- override var cost : Int = 20000 is not initialized when you are printing println("This comes First $cost") as init run first then property will initialized.
step 5:- So $cost is by default zero.

Just try this, below open var cost : Int = c
put, var costTest : Int = c. "no open keyword"
Then, on Vehicle init put,

println("This comes Second $cost $costTest") 

here you will get costTest = 1000.

Its because costTest you haven't override

Comments

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.