使用 kotlin-reflect 设置可为空的 UShort
Setting a nullable UShort using 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 类型?如果可空性是问题所在(尽管当我尝试对可为空的字符串 var 做同样的事情时这不是问题)
内联 classes 有问题。如您所知,内联 classed 仍处于实验阶段,UShort
是一个内联 class,它充当 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
...
如您所知,内联 classes 应该在编译后被忽略和删除,但是因为您将 DA
定义为可空,编译后的类型仍然是 UShort
而不是 Short
.
然而,当您在对象上调用 Int.toUShort
时,编译后的代码没有 UShort
的符号,而是转换为 Short
(因为它是一个内联 class).这就是您收到 argument type mismatch
错误的原因。因为 setter 需要一个 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
...
为什么我不能在 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 做同样的事情时这不是问题)
内联 classes 有问题。如您所知,内联 classed 仍处于实验阶段,UShort
是一个内联 class,它充当 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
...
如您所知,内联 classes 应该在编译后被忽略和删除,但是因为您将 DA
定义为可空,编译后的类型仍然是 UShort
而不是 Short
.
然而,当您在对象上调用 Int.toUShort
时,编译后的代码没有 UShort
的符号,而是转换为 Short
(因为它是一个内联 class).这就是您收到 argument type mismatch
错误的原因。因为 setter 需要一个 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
...