java.lang.Integer不能转换为Kotlin中的java.lang.Long(当初始值为null时)

如果我有以下,它的作品(即数字分配1000)

fun main(args: Array) { var number: Long ? = null // or number = 0 val simpleObject = SimpleClass() number = 1000 println("Hi + $number") } 

如果我有以下,它的作品(即数字分配1000)

 import java.util.* fun main(args: Array) { var number: Long = 0 val simpleObject = SimpleClass() number = simpleObject.getValue() println("Hi + $number") } class SimpleClass() { fun getValue(): T { return 1000 as T } } 

但是,如果我有下面,它失败了

 import java.util.* fun main(args: Array) { var number: Long? = null val simpleObject = SimpleClass() number = simpleObject.getValue() println("Hi + $number") } class SimpleClass() { fun getValue(): T { return 1000 as T } } 

报告的错误在number = simpleObject.getValue()

 Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long 

为什么当我初始化var number: Long ? = null var number: Long ? = nullvar number: Long = 0有不同的结果? 我有什么不对吗?

更新

使用下面的解决方法,结果是好的。 但是使用一个额外的临时variables。

 import java.util.* fun main(args: Array) { var number: Long? = null val simpleObject = SimpleClass() val temp = simpleObject.getValue() number = temp println("Hi + $number") } class SimpleClass() { fun getValue(): T { return 1000 as T } } 

我们来看看生成的字节码:

 fun  getValue(): T { return 1000 as T } // becomes public final getValue()Ljava/lang/Object; L0 LINENUMBER 17 L0 SIPUSH 1000 INVOKESTATIC java/lang/Integer.valueOf (I)Ljava/lang/Integer; CHECKCAST java/lang/Object ARETURN L1 LOCALVARIABLE this LSimpleClass; L0 L1 0 MAXSTACK = 1 MAXLOCALS = 1 

正如你所看到的,这个方法不会将 1000转换为Long它只是简单地确保对象是java/lang/Objecttypes的,并且返回1000作为Integer对象。

因此,你可以调用(注意:只调用)这个方法与任何types,这不会抛出exception。 但是,将结果存储在variables中会调用可能导致ClassCastException

 fun f3() { val simpleObject = SimpleClass() // L0 // LINENUMBER 16 L0 // NEW SimpleClass // DUP // INVOKESPECIAL SimpleClass. ()V // ASTORE 0 simpleObject.getValue() // no problems // L1 // LINENUMBER 17 L1 // ALOAD 0 // INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object; // POP val number = simpleObject.getValue() // throws ClassCastException1 // L2 // LINENUMBER 18 L2 // ALOAD 0 // INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object; // CHECKCAST SimpleClass // ASTORE 1 // L3 // LINENUMBER 19 L3 // RETURN // L4 // LOCALVARIABLE number LSimpleClass; L3 L4 1 // LOCALVARIABLE simpleObject LSimpleClass; L1 L4 0 // MAXSTACK = 2 // MAXLOCALS = 2 } 

但为什么把结果存储为一个Long? 抛出exception? 再次,我们来看看字节码的区别:

 var number: Long? = null | var number: Long = 0 | ACONST_NULL | LCONST_0 CHECKCAST java/lang/Long | LSTORE 0 ASTORE 0 | number = simpleObject.getValue() [both] ALOAD 1 | INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object; [both] CHECKCAST java/lang/Long | CHECKCAST java/lang/Number ASTORE 0 | INVOKEVIRTUAL java/lang/Number.longValue ()J | LSTORE 0 

正如你所看到的, Number的字节码number: Long将函数结果转换为一个Number ,然后调用Number.longValue以将该值转换为Longlong in Java)

但是,数字的字节码number: Long? 将函数结果直接投入到Long?Long in Java)导致ClassCastException

不确定,如果这种行为记录在某处。 但是, as运算符执行不安全的转换,编译器会警告:

 Warning:(21, 16) Kotlin: Unchecked cast: kotlin.Int to T 
 return 1000 as T 

是一个未经检查的转换,编译器会发出警告。 你总是返回一个Integer,但是你假装它是一个T,如果T实际上是Integer,那么这只会工作正常。 在所有其他情况下,它将会失败。

如果你选择了一个完全不相关的types,比如我不知道StringBuilder,这个问题的显而易见性会更明显:

 var number: StringBuilder? = null val simpleObject = SimpleClass() number = simpleObject.getValue() 

现在你应该认识到这是没有意义的:你调用一个应该返回一个StringBuilder的方法,但是它返回1000。