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

Kotlin中如何实现运算符继承?解决物理量类代码重复问题

解决Kotlin中物理量类的运算符代码复用问题

你的问题核心是要在多个拥有相同逻辑的类中复用运算符实现,同时保持返回具体子类类型的能力——直接用无泛型的接口/抽象类会因为返回类型不匹配卡壳,这里用泛型绑定自身类型的方案就能完美解决。

方案一:泛型抽象类(推荐,更适合有状态的类)

我们可以定义一个带泛型的抽象类,泛型参数约束为子类自身类型,这样所有通用运算符都可以在抽象类中实现,返回具体的子类类型:

abstract class PhysicalQuantity<T : PhysicalQuantity<T>>(var value: Double) {
    // 自增运算符:修改当前实例的value并返回自身(具体子类类型)
    operator fun inc(): T {
        value++
        return this as T
    }

    // 同类型加法:当前实例加上另一个同类型实例的value
    operator fun plus(other: T): T {
        value += other.value
        return this as T
    }

    // 同理可以实现自减、减法等通用运算符
    operator fun dec(): T {
        value--
        return this as T
    }
}

// Volume类继承抽象类,指定泛型参数为自身
class Volume(value: Double, unit: Unit) : PhysicalQuantity<Volume>(value) {
    var unit: Unit = unit
        private set

    enum class Unit(symbol: String){
        MILLILITER("ml"), CENTILITER("cl"), DECILITER("dl"), LITER("l"),
        TEASPOON("tsp"), TABLESPOON("tbsp"), FLUIDOUNCE("floz"), SHOT("jig"),
        GILL("gi"), CUP("cup"), PINT("pt"), QUART("qt"), GALLON("gal")
    }
}

// Mass类同样继承,指定泛型参数为自身
class Mass(value: Double, unit: Unit) : PhysicalQuantity<Mass>(value) {
    var unit: Unit = unit
        private set

    enum class Unit(symbol: String){
        GRAM("g"), DECAGRAM("dag"), HECTOGRAM("hg"), KILOGRAM("kg"),
        OUNCE("oz"), POUND("lb")
    }
}

方案二:泛型接口(适合更灵活的场景)

如果不想用抽象类,也可以用带泛型的接口,利用Kotlin的接口默认方法实现复用:

interface PhysicalQuantity<T : PhysicalQuantity<T>> {
    var value: Double

    operator fun inc(): T {
        value++
        return this as T
    }

    operator fun plus(other: T): T {
        value += other.value
        return this as T
    }
}

class Volume(override var value: Double, unit: Unit) : PhysicalQuantity<Volume> {
    var unit: Unit = unit
        private set
    // 枚举类不变
}

class Mass(override var value: Double, unit: Unit) : PhysicalQuantity<Mass> {
    var unit: Unit = unit
        private set
    // 枚举类不变
}

为什么这个方案能解决问题?

  • 泛型绑定自身:通过T : PhysicalQuantity<T>的约束,我们告诉编译器T必须是继承自PhysicalQuantity的子类,而且就是当前类自己。
  • 安全的类型转换:this as T是完全安全的,因为子类继承时明确指定了T为自身类型(比如Volume的T就是Volume),不会出现类型转换异常。
  • 代码完全复用:所有通用运算符的逻辑都只写一次,子类不需要重复实现,直接继承即可,同时返回的是具体的子类类型,符合你的需求。

额外提示

如果你的运算符需要创建新实例(而不是修改当前实例),比如加法返回一个新的Volume而不是修改原对象,那么可以在抽象类中定义一个抽象方法来创建实例,比如:

abstract class PhysicalQuantity<T : PhysicalQuantity<T>>(var value: Double) {
    protected abstract fun createNew(value: Double): T

    operator fun plus(other: T): T {
        return createNew(this.value + other.value)
    }
}

// 在Volume中实现createNew
class Volume(value: Double, val unit: Unit) : PhysicalQuantity<Volume>(value) {
    override fun createNew(value: Double): Volume {
        return Volume(value, this.unit)
    }
}

这样就能实现无副作用的算术运算,同时依然复用大部分代码。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.08 08:47:52