Kotlin中MutableMap类型子类对象为何未调用自定义set运算符?
核心原因:静态分发与函数优先级规则
当你将MyMap实例赋值给MutableMap类型变量时,编译器是基于**变量的静态类型(MutableMap)**来解析函数调用的,而非实际运行时类型(MyMap),具体规则如下:
MutableMap的set运算符是扩展函数
Kotlin里myMap["key"] = "value"这个语法糖对应的operator fun set(key: K, value: V),并不是MutableMap接口的成员函数,而是定义在kotlin.collections.Maps.kt中的扩展函数。这个扩展函数内部其实是调用了MutableMap的成员函数put(key, value)。子类的成员函数无法被静态类型匹配
你的MyMap类中定义的operator fun set是类的成员函数,但当变量的静态类型是MutableMap时,编译器在编译阶段只会查找MutableMap接口本身的成员函数,以及针对MutableMap的扩展函数,不会去识别子类新增的成员函数。因为这里的函数调用是静态分发的,编译器不会在编译时向下遍历子类的成员。静态类型为MyMap时的正常逻辑
当变量声明为MyMap类型时,编译器会优先匹配类自身的成员函数(你自定义的set),而不会去调用针对MutableMap的扩展函数,因此能正常触发你的额外逻辑。
为什么重写put方法可以解决问题?
因为put(key: K, value: V): V?是MutableMap接口定义的成员函数,Kotlin的多态规则会保证:无论变量的静态类型是MyMap还是MutableMap,运行时都会调用子类(MyMap)中重写的put方法。而MutableMap的扩展set函数内部正是调用了put,所以重写put后,myMap["key"] = "value"的语法糖最终会触发你重写的逻辑。
内容的提问来源于stack exchange,提问作者Lukor

