提问者:小点点

在Kotlin中安全转换为泛型类型时出现异常


我在kotlin中使用安全转换选项,即< code>as?当数据类型不兼容时,我仍然会遇到类转换异常,这是在我通过为执行case而编写的泛型方法执行此操作时发生的,但是,如果我直接执行转换,它会像安全转换所预期的那样返回null

class CastTest(val data: Any) {

   fun castViaGenericMethod(): TypeA? {
      return castToContext<TypeA>()
   }

   fun castDirectly(): TypeA? {
      return data as? TypeA
   }

   private fun <CONTEXT> castToContext(): CONTEXT? = data as? CONTEXT

}

< code > castViaGenericMethod()-

请建议如何做到这一点。


共1个答案

匿名用户

要解决您的问题,您可以使用< code >具体化类型:

inline fun <reified CONTEXT> castToContext() = data as? CONTEXT

为什么它没有像你预期的那样工作的原因是,泛型类型在运行时被删除了。

如果我们看一下字节码,我们会发现无论你的 CONTEXT-generic 类型写在哪里,它都变成了 java/lang/Object

private final castToContext()Ljava/lang/Object;
 L0
  LINENUMBER 12 L0
    ALOAD 0
    GETFIELD CastTest.data : Ljava/lang/Object;
    DUP
    INSTANCEOF java/lang/Object // (1)
    IFNE L1                     // (1)
    POP          // (2)
    ACONST_NULL  // (2)
   L1
    ARETURN
   L2
    LOCALVARIABLE this LCastTest; L0 L2 0
    MAXSTACK = 2
    MAXLOCALS = 1

因此,安全强制转换实际上会检查给定的对象是否不是< code>java/lang/Object (1)类型,如果是这种情况,则将值设置为< code>null。但是由于它的类型是< code>java/lang/Object,所以值只是按原样返回。然而,在调用方,字节代码看起来如下:

LINENUMBER 4 L0
ALOAD 0
INVOKESPECIAL CastTest.castToContext ()Ljava/lang/Object; // the call
CHECKCAST TypeA // the type check
ARETURN

它在调用castToContext后执行额外的CHECKCAST TypeA,然后您会得到您的ClassCastExc的,因为值没有无效(泛型类型信息在运行时被擦除)。