在运行时可以通过 is 和 !is 来检测一对象的类型。
智能的类型转换 Smart Casts
在很多情况下,我们不需要在kotlin中显示地使用类型转换操作,因为编译器会追踪 is 检查和显示的类型转换,并会自动为不可变类型的值进行类型转换,如:
fun demo(x: Any) {
if (x is String) {
print(x.length) // x is automatically cast to String
}
}
当相反的类型检查失败时,编译器能很智能地进行一个安全的类型转换,如:
if (x !is String) return
print(x.length) // x is automatically cast to String
或者在使用 && 和 || 时,编译器也会智能地推断类型,如:
// 在 `||` 右侧, x 被智能地转换成 String 类型
if (x !is String || x.length == 0) return
// 在 `&&` 右侧, X 被智能地转换成 String 类型
if (x is String && x.length > 0) {
print(x.length) // x is automatically cast to String
}
在when 表达式和 while循环中,这类智能转换同样适用,如:
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
类型不安全的转换符 as 和 类型安全转换符 as?
如果待转变量在不确定其类型是否为指定类型时,会抛出异常,如下面代码中,如果变量 y 是null,就会抛出异常:
val x: String = y as String
为了符合Java的类型转换语法,使用可空类型来处理,如:
val x: String? = y as String?
为了避免在类型转换时抛出异常,可以使用安全的转换符 as?, 在转换失败时,尽管as?后面的类型是非空的,也可以返回null:
val x: String? = y as? String
类型擦除和范型类型检查
Kotlin在编译时确保涉及泛型的操作的类型安全性,而在运行时,泛型类型的实例不保存有关其实际类型参数的信息。 例如,List <Foo>被擦除为List <*>。 通常,无法在运行时检查实例是否属于具有某些类型参数的泛型类型。
鉴于此,编译器禁止由于类型擦除而无法在运行时执行的is-checks,例如“ints is List<Int>”或“list is T”(类型参数)。 但是,您可以针对星型投影类型检查实例:
if (something is List<*>) {
something.forEach { println(it) } // items被当作是 `Any?`类型
}
类似地,当您已经静态检查实例的类型参数(在编译时)时,您可以进行is-check或者涉及该类型的非泛型部分的强制转换。 请注意,在这种情况下省略尖括号:
fun handleStrings(list: List<String>) {
if (list is ArrayList) {
// `list` 被智能地转换成 `ArrayList<String>`
}
}
带有省略类型参数的相同语法可用于不考虑类型参数的强制类型转换:“list as ArrayList”
|