【问题标题】:Setting a nullable UShort using kotlin-reflect使用 kotlin-reflect 设置可以为空的 UShort
【发布时间】:2020-10-16 18:34:58
【问题描述】:

为什么我不能在 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 类型?如果可空性是问题(尽管当我尝试对可空字符串 var 做同样的事情时这不是问题)

【问题讨论】:

  • 我想知道反射与内联类是否存在错误。

标签: kotlin kotlin-reflect


【解决方案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
   ...

【讨论】:

  • 感谢您的解释!我认为不使用 UShort 对我来说是最容易的。找到这些我很兴奋,因为 java 中的某些事情——比如一个字节被签名的事实——总是让我有点发疯,所以当我看到这些 UShort 和其他人时,我有点太粗心了。我会想出一个解决方法......也许只是让它成为一个 Int,因为 0-65535 适合 int。
  • 不客气。如您所知,内联类只是一个精美的包装器。它不会删除您有问题的符号位:D
猜你喜欢
  • 1970-01-01
  • 2017-10-24
  • 2019-01-05
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2019-06-11
  • 1970-01-01
  • 2019-06-15
相关资源
最近更新 更多