Kotlin IllegalAccessError用+ =和 – =代表接口
我已经定义了这个类:
class NeverNullMap(private val backing: MutableMap = mutableMapOf(), val default: () -> V): MutableMap by backing { override operator fun get(key: K): V = backing.getOrPut(key, default) }
我可以像这样完美地使用它:
fun main(args: Array) { val myMap = NeverNullMap {0} println(myMap["test"]) myMap["test"] = myMap["test"] + 10 println(myMap["test"]) }
如预期的那样,产出是:
0 10
但是,当我尝试将其更改为:
fun main(args: Array) { val myMap = NeverNullMap {0} println(myMap["test"]) myMap["test"] += 10 println(myMap["test"]) }
我得到:
Exception in thread "main" java.lang.IllegalAccessError: tried to access method kotlin.collections.MapsKt__MapsKt.set(Ljava/util/Map;Ljava/lang/Object;Ljava/lang/Object;)V from class Day08Kt at Day08Kt.main(Day08.kt:10)
为什么发生这种情况?
编辑:
挖掘一点反编译的代码都得到编译完全不同的代码。
在没有+=
的工作版本中,它被编译为:
Map var2 = (Map)myMap; String var3 = "test"; Integer var4 = ((Number)myMap.get("test")).intValue() + 10; var2.put(var3, var4);
非工作版本被编译为:
MapsKt.set(myMap, "test", ((Number)myMap.get("test")).intValue() + 10);
所以它调用这个函数: https : //github.com/JetBrains/kotlin/blob/1.2.0/libraries/stdlib/src/kotlin/collections/Maps.kt#L175
我仍然不知道为什么会产生错误,为什么第一个版本表现不一样。
编辑: YouTrack链接到报告
编辑:是的,这是一个错误,它已被合并到KT-14227 :
使用带有
plusAssign
运算符的MutableMap.set
时会生成不正确的代码
在编译(或在这种情况下反编译)之后, MapsKt.set
变成一个private
方法:
@InlineOnly private static final void set(@NotNull Map $receiver, Object key, Object value) { Intrinsics.checkParameterIsNotNull($receiver, "$receiver"); $receiver.put(key, value); }
这解释了IllegalAccessError
。
现在,至于为什么它是私人的,我只是猜测,但我觉得这可能是由于这个:
@ usbpc102指出@InlineOnly
确实是private
方法的原因 。
@InlineOnly
指定不应该直接调用该方法:
指定不应该在没有内联的情况下直接调用这个函数
所以我觉得这是一个情况,即电话应该已经内联,但事实并非如此。
如果这个调用被内联了,那么编译的代码就会与工作版本几乎相同了,因为这个方法只包含了一个调用。
我怀疑这是由于编译器错误。
- Kotlin higherorder函数(可调用引用)编译器崩溃
- 删除Kotlin中另一个字符串中出现的字符
- jackson@JsonIgnoreProperties多个字段与Kotlin
- android – 运行应用程序失败,错误“com.android.builder.dexing.DexArchiveMergerException:无法合并dex’
- 基于科林地图的属性和jackson不工作 – 委托点不同的地图,即地图属性
- 如何避免返回SAM接口的函数的对象expression式
- 无法在Kotlin中使用Jackson分析json
- 在kotlin中重新创建对象
- readLine()后无法使用.toChar()