问题描述
为什么我不能在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做同样的事情时这不是问题)
解决方法
内联类存在问题。如您所知,内联类仍处于试验阶段,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
...