在Kotlin中安全类型通用类型时获取异常

时间:2018-11-21 08:07:19

标签: java kotlin casting

我在kotlin中使用安全转换选项,即as?仍然在数据类型不兼容时收到类转换异常,当我通过编写用于执行大小写的通用方法来执行此操作时,会发生这种情况如果我直接执行转换,则返回的值将为安全转换所期望的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

}

castViaGenericMethod()->当数据不是TypeA类型时,此方法将引发ClassCastException。 castDirectly()->无法进行强制转换时,此方法返回null。

请建议如何完成。

1 个答案:

答案 0 :(得分:2)

要解决您的问题,您可以使用reified type

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

之所以无法按预期工作的原因是,泛型在运行时被擦除了。

如果我们看一下字节码,就会发现在各处写有CONTEXT通用类型的地方,它变成了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

因此,安全类型转换实际上会检查给定对象是否不是java/lang/Object(1)类型,并在这种情况下将要返回的值设置为null。但是由于它是java/lang/Object类型的值,因此仅按原样返回该值。但是在调用方,字节码如下所示:

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

它在调用CHECKCAST TypeA之后执行了另外的castToContext,并且您得到了ClassCastException,因为该值未为空(在运行时删除了通用类型信息)。