如果我有以下,它的工作原理(即数字得分1000)
fun main(args: Array<String>) {
var number: Long ? = null // or number = 0
val simpleObject = SimpleClass()
number = 1000
println("Hi + $number")
}
Run Code Online (Sandbox Code Playgroud)
如果我有以下,它的工作原理(即数字得分1000)
import java.util.*
fun main(args: Array<String>) {
var number: Long = 0
val simpleObject = SimpleClass()
number = simpleObject.getValue<Long>()
println("Hi + $number")
}
class SimpleClass() {
fun <T>getValue(): T {
return 1000 as T
}
}
Run Code Online (Sandbox Code Playgroud)
但如果我有下面的内容,那就失败了
import java.util.*
fun main(args: Array<String>) {
var number: Long? = null
val simpleObject = SimpleClass()
number = simpleObject.getValue<Long>()
println("Hi + $number")
}
class SimpleClass() {
fun <T>getValue(): T {
return 1000 as T
}
}
Run Code Online (Sandbox Code Playgroud)
报告的错误是number = simpleObject.getValue<Long>()
在线
Exception in thread "main" java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.Long
Run Code Online (Sandbox Code Playgroud)
为什么我初始化var number: Long ? = null
并var number: Long = 0
得到不同的结果?我有什么不对吗?
更新
使用下面的解决方法,结果是可以的.但是使用了额外的临时变量.
import java.util.*
fun main(args: Array<String>) {
var number: Long? = null
val simpleObject = SimpleClass()
val temp = simpleObject.getValue<Long>()
number = temp
println("Hi + $number")
}
class SimpleClass() {
fun <T>getValue(): T {
return 1000 as T
}
}
Run Code Online (Sandbox Code Playgroud)
我们来看看生成的字节码:
fun <T> 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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,此方法不会 1000
转换为Long
它只是确保对象是类型java/lang/Object
(嗯,它是)并返回1000
作为Integer
对象.
因此,您可以使用任何类型调用(注意:仅调用)此方法,这不会引发异常.但是,将结果存储在变量中会调用可能导致的实际转换ClassCastException
fun f3() {
val simpleObject = SimpleClass()
// L0
// LINENUMBER 16 L0
// NEW SimpleClass
// DUP
// INVOKESPECIAL SimpleClass.<init> ()V
// ASTORE 0
simpleObject.getValue<SimpleClass>() // no problems
// L1
// LINENUMBER 17 L1
// ALOAD 0
// INVOKEVIRTUAL SimpleClass.getValue ()Ljava/lang/Object;
// POP
val number = simpleObject.getValue<SimpleClass>() // 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
}
Run Code Online (Sandbox Code Playgroud)
但为什么将结果存储为Long?
抛出异常?再说一次,我们来看看字节码的差异:
var number: Long? = null | var number: Long = 0
|
ACONST_NULL | LCONST_0
CHECKCAST java/lang/Long | LSTORE 0
ASTORE 0 |
number = simpleObject.getValue<Long>() [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
Run Code Online (Sandbox Code Playgroud)
正如您所看到的,用于number: Long
将函数结果转换为a Number
然后调用Number.longValue
以将值转换为a Long
(long
在Java中)的字节码
但是,用于number: Long?
将函数结果直接转换为Long?
(Long
在Java中)导致的字节码ClassCastException
.
不确定,如果这种行为记录在某处.但是,as
操作员执行不安全的强制转换,编译器会警告它:
Warning:(21, 16) Kotlin: Unchecked cast: kotlin.Int to T
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
5844 次 |
最近记录: |