You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Kotlin中属性覆盖为何导致父类主构造函数属性值为0?附Java对比

为什么Kotlin子类覆盖属性时,父类构造函数中的cost值为0?(结合Java对比)

先来看你的测试场景:

你写了这样一段Kotlin代码:

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()
}

运行后输出:

This comes First 0
This comes Second 20000
cost = 20000

而当你注释掉override var cost: Int = 20000这一行后,输出变成了:

This comes First 1000
This comes Second 1000
cost = 1000

这个差异的核心,要从Kotlin的属性覆盖机制和初始化顺序说起,咱们再对比Java的行为来帮你理解:

一、Kotlin这边的核心原因

在Kotlin中,用override修饰的属性是真正的重写,而非Java中的字段隐藏。也就是说,当子类Vehicle用override var cost重写父类Car的cost属性时,父类中的cost实际上指向的是子类的这个属性实例,而非父类自己的独立字段。

而Kotlin的对象初始化顺序是这样的:

  1. 调用子类构造函数时,先把参数传递给父类构造函数(这里就是把1000传给Car的c)
  2. 进入父类的初始化流程:此时父类要给cost赋值,但因为子类已经重写了这个属性,父类操作的其实是子类的cost属性——但此时子类的属性还没有被初始化(子类的属性初始化是在父类的init块执行完之后才会进行),所以cost此时是Int类型的默认值0
  3. 父类的init块执行,打印出This comes First 0
  4. 父类初始化完成后,才会执行子类的属性初始化,把cost赋值为20000
  5. 子类的init块执行,打印This comes Second 20000
  6. 最后调用show()方法,自然打印的是已经初始化完成的子类cost值20000

如果注释掉override那一行,子类就没有重写父类的cost,此时父类的cost是自己的独立属性,会被赋值为传入的1000,父类init块打印1000,子类继承这个属性值,所以后续输出都是1000。

二、对比Java的行为,你就能更清楚差异

在Java中,字段是不能被重写的,子类声明同名字段只是隐藏了父类的字段,二者是完全独立的两个字段:

比如把你的代码改成Java版本:

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

class Vehicle extends Car {
    int cost = 20000;
    public Vehicle(int cc) {
        super(cc);
        System.out.println("This comes Second " + cost);
    }
    public void show() {
        System.out.println("cost = " + cost);
    }
}

public class Main {
    public static void main(String[] args) {
        Vehicle vehicle = new Vehicle(1000);
        vehicle.show();
    }
}

这段Java代码的输出会是:

This comes First 1000
This comes Second 20000
cost = 20000

为什么和Kotlin的结果不一样?因为Java中父类的cost和子类的cost是两个不同的字段:

  • 父类构造函数中操作的是自己的cost字段,赋值为1000,所以打印1000
  • 子类的cost是自己的独立字段,在父类构造完成后才初始化赋值为20000,所以后续打印的是子类的字段值

这就是Kotlin和Java在属性/字段重写/隐藏上的核心差异:Kotlin的override var是真正的重写,父类会直接引用子类的属性;而Java的同名字段只是隐藏,父类和子类各有自己的字段。

内容的提问来源于stack exchange,提问作者Vikas Acharya

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.07 09:42:33