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

Kotlin实现父类方法返回调用它的子类实例的问题

问题:让继承类的方法返回自身类型而非父类类型

问题描述

我有一个Quadrilateral类,继承自父类Polygon的translate方法,Polygon实现了Shape接口。当前Polygon的translate方法返回Polygon实例,但Quadrilateral有自己的特有方法,调用Quadrilateral实例的translate后,无法直接调用这些特有方法。

实际场景存在更深的继承结构(比如Square或Rectangle继承自Quadrilateral),我希望在父类中仅实现一次这类方法,但调用时始终返回调用该方法的子类的新实例。

尝试用泛型+强制类型转换实现时,遇到如下异常:

Exception in thread "main" java.lang.ClassCastException: class Polygon cannot be cast to class Quadrilateral (Polygon and Quadrilateral are in unnamed module of loader 'app')
    at MainKt.main(Main.kt:10)

基础示例代码(无法运行)

interface Shape {
    fun translate(translation: Double): Shape
}

open class Polygon(open val vertices: List<Pair<Double, Double>>) : Shape {
    override fun translate(translation: Double): Polygon {
        return Polygon(vertices.map { Pair(it.first + translation, it.second + translation) })
    }
}

class Quadrilateral(override val vertices: List<Pair<Double, Double>>) : Polygon(vertices) {
    fun scale(factor: Double): Quadrilateral {
        return Quadrilateral(vertices.map { Pair(it.first * factor, it.second * factor) })
    }
}

fun main(args: Array<String>) {
    val a = Pair(0.0, 0.0)
    val b = Pair(0.1, 0.0)
    val c = Pair(1.0, 1.0)
    val d = Pair(0.0, 1.0)

    val rect = Quadrilateral(listOf(a, b, c, d))
    // 编译报错:Polygon没有scale方法
    println(rect.translate(5.0).scale(5.0))
}

泛型尝试代码

interface Shape<T: Shape<T>> {
    fun translate(translation: Double): T
}

open class Polygon<T : Polygon<T>>(open val vertices: List<Pair<Double, Double>>) : Shape<T> {
    override fun translate(translation: Double): T {
        // 强制转换导致ClassCastException
        return Polygon(vertices.map { Pair(it.first + translation, it.second + translation) }) as T
    }
}

class Quadrilateral(override val vertices: List<Pair<Double, Double>>) : Polygon<Quadrilateral>(vertices) {
    fun scale(factor: Double): Quadrilateral {
        return Quadrilateral(vertices.map { Pair(it.first * factor, it.second * factor) })
    }
}

fun main(args: Array<String>) {
    val a = Pair(0.0, 0.0)
    val b = Pair(0.1, 0.0)
    val c = Pair(1.0, 1.0)
    val d = Pair(0.0, 1.0)

    val rect = Quadrilateral(listOf(a, b, c, d))
    println(rect.translate(5.0).scale(5.0))
}

可行解决方案:抽象工厂方法+泛型

核心思路是让父类定义抽象的实例创建方法,由子类实现自身实例的创建逻辑,父类的业务方法(比如translate)调用该方法生成实例,避免强制类型转换。

修改后的代码:

interface Shape<T : Shape<T>> {
    fun translate(translation: Double): T
}

// 改为抽象类,新增抽象方法让子类实现实例创建
open abstract class Polygon<T : Polygon<T>>(open val vertices: List<Pair<Double, Double>>) : Shape<T> {
    // 子类必须实现:用新顶点创建自身实例
    protected abstract fun createNewInstance(vertices: List<Pair<Double, Double>>): T

    override fun translate(translation: Double): T {
        val translatedVertices = vertices.map { Pair(it.first + translation, it.second + translation) }
        // 调用子类的实例创建方法
        return createNewInstance(translatedVertices)
    }
}

class Quadrilateral(override val vertices: List<Pair<Double, Double>>) : Polygon<Quadrilateral>(vertices) {
    override fun createNewInstance(vertices: List<Pair<Double, Double>>): Quadrilateral {
        return Quadrilateral(vertices)
    }

    fun scale(factor: Double): Quadrilateral {
        val scaledVertices = vertices.map { Pair(it.first * factor, it.second * factor) }
        return createNewInstance(scaledVertices)
    }
}

// 更深层次的子类示例:Rectangle
class Rectangle(val width: Double, val height: Double, vertices: List<Pair<Double, Double>>) : Polygon<Rectangle>(vertices) {
    override fun createNewInstance(vertices: List<Pair<Double, Double>>): Rectangle {
        // 可根据需求重新计算宽高,这里直接复用原有宽高示例
        return Rectangle(width, height, vertices)
    }

    fun getArea(): Double {
        return width * height
    }
}

fun main(args: Array<String>) {
    val a = Pair(0.0, 0.0)
    val b = Pair(0.1, 0.0)
    val c = Pair(1.0, 1.0)
    val d = Pair(0.0, 1.0)

    val rect = Quadrilateral(listOf(a, b, c, d))
    // 现在可以链式调用translate和scale
    println(rect.translate(5.0).scale(5.0).vertices)

    val rectangle = Rectangle(1.0, 1.0, listOf(a, Pair(1.0,0.0), Pair(1.0,1.0), d))
    // Rectangle调用translate后仍可调用自身方法getArea
    println(rectangle.translate(2.0).getArea())
}

方案优势

  • 父类仅需实现一次业务逻辑(比如translate的顶点计算),子类无需重复编写
  • 避免了不安全的强制类型转换,消除ClassCastException
  • 支持任意深度的继承结构,子类只需实现createNewInstance即可保证方法返回自身类型
  • 符合开闭原则,新增子类时无需修改父类代码

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.02 13:53:27