Kotlin IllegalAccessError,带有+ =和-=用于委托接口 [英] Kotlin IllegalAccessError with += and -= for delegated Interface

查看:68
本文介绍了Kotlin IllegalAccessError,带有+ =和-=用于委托接口的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我已经定义了此类:

class NeverNullMap<K, V>(private val backing: MutableMap<K, V> = mutableMapOf(), val default: () -> V): MutableMap<K, V> by backing {
    override operator fun get(key: K): V = backing.getOrPut(key, default)
}

我可以像这样完美地使用它:

And I can use it perfectly fine like this:

fun main(args: Array<String>) {
    val myMap = NeverNullMap<String, Int> {0}
    println(myMap["test"])
    myMap["test"] = myMap["test"] + 10
    println(myMap["test"])
}

如预期的那样,输出为:

as expected the output is:

0
10

但是当我尝试将其更改为:

But when I try to change it to:

fun main(args: Array<String>) {
    val myMap = NeverNullMap<String, Int> {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)

为什么会这样?

深入研究反编译代码,它们都将被编译为完全不同的代码.

Digging a bit into decompiled code both get compiled to completly diffrent code.

在没有+=的工作版本中,它被编译为:

In the working version without the += it gets compiled to:

  Map var2 = (Map)myMap;
  String var3 = "test";
  Integer var4 = ((Number)myMap.get("test")).intValue() + 10;
  var2.put(var3, var4);

无法正常运行的版本被编译为:

The non working version gets compiled to:

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

我仍然不知道为什么会产生错误,只是为什么第一个版本的行为会有所不同.

I still have no idea why that produces the Error, just why the first version behaves diffrently.

指向报告的YouTrack链接

推荐答案

是的,这是一个错误,已与

yes, this is a bug, it has been merged with KT-14227:

MutableMap.setplusAssign运算符一起使用时会生成不正确的代码

Incorrect code is generated when using MutableMap.set with plusAssign operator


编译(在这种情况下为反编译)后,将MapsKt.set转换为private方法:


After compilation (or decompilation, in this case), MapsKt.set is turned into a private method:

@InlineOnly
private static final void set(@NotNull Map $receiver, Object key, Object value) {
    Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
    $receiver.put(key, value);
}

这说明了IllegalAccessError.

现在,关于为什么它是私有的,我只是在推测,但我觉得可能是由于以下原因:

@ usbpc102 指出

@usbpc102 pointed out that @InlineOnly is indeed the reason for the method being private.

@InlineOnly指定永远不要直接调用该方法:

@InlineOnly specifies that the method should never be called directly:

指定不应在没有内联的情况下直接调用此函数

Specifies that this function should not be called directly without inlining

所以我觉得这是内嵌对set 的调用的情况,但事实并非如此.

so I feel like this is a case where the call to set should have been inlined, but it was not.

如果该调用已内联,则最终将获得与工作版本几乎相同的已编译代码,因为该方法仅包含对put的调用.

Had the call been inlined, you would have ended up with compiled code that is practically identical to the working version, since the method only contains a call to put.

我怀疑这是由于编译器错误所致.

I suspect this is due to a compiler bug.

这篇关于Kotlin IllegalAccessError,带有+ =和-=用于委托接口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆