为什么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检查。 isexpression式并不要求左侧是任何特定的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); } }