Mar*_*ger 5 generics casting classcastexception kotlin
在下面,我有一个fun <T : Number> sum(list : List<T>) : T
带有类型参数的泛型函数T : Number
。
在函数中,我将列表的数字总结为 asum : Double
并将总和最后转换为return sum as T
。
例如,如果Int
传递了一个列表,我也会返回一个Int
- 并且这有效。
fun <T : Number> sum(list : List<T>) : T {
var sum = 0.0
for(x in list)
sum += x.toDouble()
return sum as T
}
fun main() { println(sum(listOf(1,2,3))) } // prints 6
Run Code Online (Sandbox Code Playgroud)
然而,以下内容不起作用,我想知道为什么上面的通用函数有效,但直接将 a 转换Double
为 anInt
却不起作用。
fun main() {
val d : Double = 6.0
val i = d as Int // java.lang.ClassCastException: java.lang.Double cannot be cast to java.lang.Integer
println(i)
}
Run Code Online (Sandbox Code Playgroud)
我不得不承认,我预计这两种情况都会失败,但令人惊讶的是,通用函数有效,但我不知道为什么。
所以问题是:为什么泛型函数可以工作,并且在从 Double 转换为 Int 时不会抛出 ClassCastException?
请注意,在第一个“有效”的代码片段中,您实际上并未将结果转换为Int
. 如果您使用 IntelliJ,它应该将转换标记为“未经检查的转换”。这意味着在运行时,不会检查是否sum
实际上可以转换为 type T
。它只检查是否sum
是 a Number
,仅此而已。不执行任何其他操作。
通过打印可以看到返回值仍然是 a Double
,而不是 an Int
:
println(sum(listOf<Int>(1,2,3)) is Int) // false
println(sum(listOf<Int>(1,2,3)) is Double) // true
Run Code Online (Sandbox Code Playgroud)
正如其他答案所解释的,这是因为类型擦除。
6
您仍然看到但没有看到的原因6.0
有点复杂。Kotlin 编译器认为sum
此处的调用应返回 an Int
(此时类型尚未被删除),因此它找到println
采用 an 的重载Int
,该重载内联到 JavaSystem.out.prinln(int)
方法。要调用此方法,编译器必须生成将返回的类型擦除的代码转换为Number
,因此它调用.sum
int
Number.intValue
因此,这就是生成的内容:
33: invokestatic #69 // Method sum:(Ljava/util/List;)Ljava/lang/Number;
36: invokevirtual #73 // Method java/lang/Number.intValue:()I
39: invokevirtual #79 // Method java/io/PrintStream.println:(I)V
Run Code Online (Sandbox Code Playgroud)
如果您强制编译器调用pritnln(Any)
,那么它将打印6.0
:
val any: Any = sum(listOf<Int>(1,2,3))
println(any)
Run Code Online (Sandbox Code Playgroud)
归档时间: |
|
查看次数: |
499 次 |
最近记录: |