为什么Kotlin中的’as’并没有在这种情况下施展
为什么Java在这种情况下打印false
?
我今天就开始写Kotlin,而我想用generics来施放参数,但结果是意外的。 而我不知道为什么?
fun main(args: Array) { var t = TEST() print(t.returns("12") is Int) // print false } @Suppress("UNCHECKED_CAST") class TEST { fun returns(r: R): T { return r as T } }
对不起,如果我的英文不好。
由于generics在JVM上的工作原理,这是因为您忽略@Suppress("UNCHECKED_CAST")
给出的警告。
简单地把TEST
类编译成以下的java类:
class TEST { Object returns(Object r) { return r; } }
因为generics在运行时没有被通用化,所以这意味着generics的generics没有意义。
解决这个问题的一个方法是使用kotlin的被泛化的generics,一个内联函数和一个匿名类来强制一个真正的强制转换,而不是被简化为Object
:
open class TEST { open fun returns(r: R): T { return r as T } } inline fun createTest(): TEST { return object : TEST() { override fun returns(r: R): T { return r as T } } } fun main(args: Array) { var t = createTest() print(t.returns("12") is Int) // Causes classcastexception }
Javagenerics有types擦除 。 这使得JVM语言很难实现泛化的generics。 有些语言像Scala那样,有些语言如Kotlin不会 。
这个未经检查的演员是真的没有检查,因此警告。 如果没有泛化generics,你不能做适当的检查,编译器只会在运行时在generics和非generics代码的边界进行types检查。 因为你的例子没有真正的非generics部分,所以没有这样的types检查。 is
expression式并不要求左侧是任何特定的types,所以即使运行时检查也被省略,就像在Java中一样。
考虑下面的例子,返回值存储在一个variables中:
fun main(args: Array) { var t = TEST() var k = t.returns("12") // runtime error here print(k is Int) } @Suppress("UNCHECKED_CAST") class TEST { fun returns(r: R): T { return r as T } } ... Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Number at MainKt.main(main.kt:3)
Kotlin在许多地方使用Java-s型检查器。 如果考虑等效的Java代码,则其行为方式相同:
public class JMain { public static void main(String[] args) { TEST t = new TEST<>(); System.out.println(t.returns("12") instanceof Integer); // false } static class TEST { @SuppressWarnings("unchecked") public T returns(R r) { return (T)r; } } }
结果是false
而不是一个ClassCastException
是因为generics参数types擦除发生在编译时。
- 如果types参数是无界的,则将genericstypes中的所有types参数替换为它们的边界或对象 。 所产生的字节码因此只包含普通的类,接口和方法。
- 如果需要,插入types会强制转换以保持types安全。
所以上面的代码在你的问题返回types的returns
方法是Object
而不是Integer
。 并且即使没有额外的转换,也可以将String
分配给Object
。 所以你检查一个String
是否是一个Int
将永远是false
。
另一种情况是声明一个具有有界参数types的类 ,这将抛出一个ClassCastException
。 例如:
@Suppress("UNCHECKED_CAST") class TEST { fun returns(r: R): T { return r as T } } fun main(args: Array) { var t = TEST() print(t.returns("12") is Int) // ^--- throws ClassCastException }
types擦除后的有界参数types的generics类如下所示:
public final class TEST{ public int returns(String value){ return ((Integer) value); } }