使用Kotlin-reflect设置可为空的UShort

时间:2020-10-16 18:34:58

标签: kotlin kotlin-reflect

为什么我不能在Kotlin中使用反射设置UShort?我将问题提取到单元测试中。

我的测试如下:

class Junk {
    var DA: UShort? = null
}

class Tests {
    @Test
    fun testSetShort() {
        var uut = Junk()
        val value = 100
        val expect = 100

        val properties: Collection<KProperty<*>> = Junk::class.memberProperties
        val property = properties.find { property -> property.name == "DA" }
        if (property is KMutableProperty<*>) {
            property.setter.call(uut, value.toUShort())  /* FAILS HERE */
        }

        assertEquals(expect, uut.DA)
        System.err.println("ok")
    }
}

结果是

argument type mismatch
java.lang.IllegalArgumentException: argument type mismatch
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:498)
    at kotlin.reflect.jvm.internal.calls.CallerImpl$Method.callMethod(CallerImpl.kt:97)
    at kotlin.reflect.jvm.internal.calls.CallerImpl$Method$Instance.call(CallerImpl.kt:113)
    at kotlin.reflect.jvm.internal.calls.InlineClassAwareCaller.call(InlineClassAwareCaller.kt:142)
    at kotlin.reflect.jvm.internal.KCallableImpl.call(KCallableImpl.kt:108)
    at Tests.testSetShort(testSetUshort.kt:24)

我尝试过的事情:

  • 强制 value 成为UShort类型?以防可空性成为问题(尽管当我尝试对可为空的String var做同样的事情时这不是问题)

1 个答案:

答案 0 :(得分:1)

内联类存在问题。如您所知,内联类仍处于试验阶段,UShort是内联类,充当Short的包装器:

public inline class UShort @PublishedApi internal constructor(@PublishedApi internal val data: Short) : Comparable<UShort>

让我们看一下您的代码的字节码。这是您的DA属性的摘要字节码:

private Lkotlin/UShort; DA
  @Lorg/jetbrains/annotations/Nullable;() // invisible

  // access flags 0x11
  public final getDA-XRpZGF0()Lkotlin/UShort;
  @Lorg/jetbrains/annotations/Nullable;() // invisible
  
    ...

  public final setDA-ffyZV3s(Lkotlin/UShort;)V
    // annotable parameter count: 1 (visible)
    // annotable parameter count: 1 (invisible)
    @Lorg/jetbrains/annotations/Nullable;() // invisible, parameter 0

    ...

您知道内联类在编译后应被忽略并删除,但是由于您将DA定义为可为空,因此编译后的类型仍然是UShort而不是Short

但是,当您在对象上调用Int.toUShort时,编译后的代码没有UShort的符号,而是转换为Short(因为它是一个内联类,所以应该这样)。这就是为什么出现argument type mismatch错误的原因。因为设置器需要一个UShort,但是您却给了它一个Short
这就解释了为什么您的代码使用Short而非UShort成功运行的原因。

无论如何,如果您确实需要在代码中使用UShort,则不应将其设置为可为空,而应使用lateinit var,它可以正常工作。因为如果它不能为空,那么DA属性的类型将在编译后为Short

var DA: UShort = 0u

//bytecode:

 private S DA   // S is JVM type for Short

  // access flags 0x11
  public final getDA-Mh2AYeg()S
   ...

  // access flags 0x11
  public final setDA-xj2QHRw(S)V
   ...
相关问题