Kotlin 适配器模式:getter 函数上的重复方法名称错误

Kotlin adapter pattern: Duplicate method name error on getter function

只是简单的 kotlin 代码来演示四人组设计模式中的适配器模式。我今天有一个关于这个的演讲,但我做不到。好难过。我不想添加太多细节,但他们不允许我在没有太多细节的情况下 post。

异常:

Exception in thread "main" java.lang.ClassFormatError: Duplicate method name "getRadius" with signature "()I" in class file RoundHole
 at java.lang.ClassLoader.defineClass1 (ClassLoader.java:-2) 
 at java.lang.ClassLoader.defineClass (ClassLoader.java:756) 
 at java.security.SecureClassLoader.defineClass (SecureClassLoader.java:142) 

代码:

interface WorkingWithRound {
    fun getRadius(): Int
}

open class RoundPeg(val radius: Int = 0): WorkingWithRound {
    override fun getRadius() = radius
}

class RoundHole(val radius: Int = 0): WorkingWithRound {
    override fun getRadius() = radius
    
    fun fit(peg: RoundPeg) {
        println(getRadius() >= peg.getRadius())
    }
}

class SquarePeg(val width: Int = 0)

class SquarePegAdapter(val speg: SquarePeg): RoundPeg() {
    override fun getRadius() = (speg.width / 2 * 1.4).toInt()
}


fun main() {
    val hole = RoundHole(5)
    val rpeg = RoundPeg(5)
    hole.fit(rpeg)

    val small_sqpeg = SquarePeg(5)
    val large_sqpeg = SquarePeg(10)
    
    //hole.fit(small_sqpeg) // this won't compile (incompatible types)

    val small_sqpeg_adapter = SquarePegAdapter(small_sqpeg)
    val large_sqpeg_adapter = SquarePegAdapter(large_sqpeg)
    
    hole.fit(small_sqpeg_adapter) // true
    hole.fit(large_sqpeg_adapter) // false
}

Kotlin 为实例变量生成 getter 方法,因此出现错误。解决问题的几个选项

  • radius 变量设为私有
    open class RoundPeg(private val radius: Int = 0): WorkingWithRound
  • @JvmField标记radius指示编译器不要生成任何getter
    class RoundHole(@JvmField val radius: Int = 0): WorkingWithRound

我认为如果接口定义 property 而不是 getter 方法,这会更简单(同时避免编译问题):

interface WorkingWithRound {
    val radius: Int
}

编译成几乎相同的字节码;但意图更明确,然后可以直接在构造函数中实现:

open class RoundPeg(override val radius: Int = 0): WorkingWithRound

class RoundHole(override val radius: Int = 0): WorkingWithRound {
    fun fit(peg: RoundPeg) {
        println(radius >= peg.radius)
    }
}

SquarePegAdapter 可以简化,因为它不再需要存储 speg 值,但可以简单地将其用作 属性:

的初始化程序
class SquarePegAdapter(speg: SquarePeg): RoundPeg() {
    override val radius = (speg.width / 2 * 1.4).toInt()
}

其余代码无需更改。