首页 > 解决方案 > 使用 kotlin-reflect 设置可以为空的 UShort

问题描述

为什么我不能在 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)

我尝试过的事情:

标签: kotlinkotlin-reflect

解决方案


这是内联类的问题。如您所知,内联类仍然是实验性的,并且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为可为空,所以编译后的类型仍然UShortShort.

但是,当您调用Int.toUShort一个对象时,编译后的代码没有任何符号,UShort而是转换为Short(因为它是一个内联类应该如此)。这就是为什么你得到一个argument type mismatch错误。因为 setter 需要 aUShort但你给它 a Short
这就解释了为什么您的代码使用Short而不是UShort.

无论如何,如果你真的需要UShort在你的代码中使用,你不应该让它可以为空,lateinit var而是使用 a 并且它工作正常。因为如果它不可为空,则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
   ...

推荐阅读