我正在try 编写我自己的LinkedHashMap子类,它在更新时执行一些额外的功能.这看起来类似于以下内容:

class MyMap(): LinkedHashMap<String, String>() {
    operator fun set(key: String, value: String) {
        super.put(key, value)
        doSomethingWith(value)
    }
}

然后,我声明一个类型为MutableMap<String, String>的变量,并为其分配一个类型为MyMap的对象:

val myMap: MutableMap<String, String> = MyMap()

但是,如果我现在try 使用修改后的运算符方法

myMap["key"] = "value"

我编写的方法没有被调用,但是在Kotlin(kotlin/collections/Maps.kt)中为MuableMap定义的扩展函数被调用了.这一部分我不理解,因为我的变量的声明类型是一个接口(所以静态解析方法应该是不可能的),而动态类型是MyMap,它定义了set操作符,并且没有扩展函数(这两种方式都不能在类本身中隐藏实际的实现).如果我将变量的静态类型声明为MyMap,则会像预期的那样调用我的函数.如果我的变量声明的类型不同,为什么Kotlin要通过父类来解析函数?

免责声明:我将通过覆盖put函数来解决这个问题,所以我的问题不是关于具体的解决方案,而是更多地是关于为这个IMO奇怪的行为找到一个解释.

推荐答案

您的set方法在它的任何超类或它实现的任何接口中都没有override任何东西,所以首先不可能通过MutableMap接口动态解析到您的set方法.事实上,层次 struct 中没有实例方法set可供您重写.set是一个扩展函数!

operator fun <K, V> MutableMap<K, V>.set(key: K, value: V)

基本上,上面的扩展函数和您编写的set是两个不相关的可调用函数.当编译时类型为MutableMap时,编译器才能看到前者.

当编译时间类型为MyMap时,它将解析为your set,因为它总是优先于扩展函数.关于确切的优先顺序,请参见here.

在本例中,您can实际上通过重新声明您自己的扩展with the same signature来覆盖(一般意义上不是override)内置set:

operator fun <K, V> MutableMap<K, V>.set(key: K, value: V) {
    ...
}

这是因为包范围内的扩展函数和显式导入的扩展函数的优先级高于implicitly imported个扩展函数.kotlin.collections包中的内置set是隐式导入的.

但如果你想要动态解析,那是行不通的.

Kotlin相关问答推荐

在KMP中使用koin将来自Android的上下文注入到SQLDelight Driver中

Kotlin和JavaFX:绑定行为奇怪

在 Kotlin 中实现并输入 Either

在 Kotlin 中将两个字节转换为 UIn16

Kotlin 协程:flatMapLatest 什么都不发出

如何从 Period.between() 返回的字符串中提取信息? (Kotlin )

有什么方法可以要求在 kotlin 中的类型参数上进行注释?

Kotlin - 协程未按预期执行

如何在 Kotlin 中实现 Composition UML 关系?

为什么 Kotlin 扩展运算符在传递原始可变参数时需要 toTypedArray()?

如何在主线程上使用 Kotlin 协程 await()

使用 Kotlin 创建新目录,Mkdir() 不起作用

Kotlin:如何从另一个类访问字段?

Kotlin 接口属性:只需要公共 getter 而没有公共 setter

Kotlin:具有多个不同类型设置器的单个属性

Kotlin lambda 语法混淆

android Room 将 Null 作为非 Null 类型返回

有没有办法在Kotlin中设置一个私有常量

kotlin中密封类和密封接口的区别是什么

Kotlin中的函数接口