在运行时可以执行类型检查以检查对象的类型。类型转换将对象强制转换为不同的类型
is
和 !is
可以使用is
或者!is
来判断实例是不是指定的类型
fun main() {
var obj : Any = "cast"
if (obj is String) {
println(obj.length) // 4
}
obj = 123
if (obj !is String) {
print("Not a String") // Not a String
} else {
println(obj.length)
}
}
智能转换
正常情况下,当使用了is
或者!is
判断实例类型时,如果返回的是true
则会自动转成相应的类型,不需要再显示的进行类型转换了
fun main() {
var obj : Any = "cast"
if (obj is String) {
println(obj.length) // 4
}
// println(obj.length) // 报错 - Unresolved reference: length
if (obj !is String) return
println(obj.length)
}
fun main() {
val x : Any = ""
if (x !is String || x.length == 0) return
if (x is String && x.length > 0) {
print(x.length)
}
}
在when
中使用
when (x) {
is Int -> print(x + 1)
is String -> print(x.length + 1)
is IntArray -> print(x.sum())
}
注意,只有当编译器能够保证变量在检查和使用之间不会改变时,智能强制转换才会起作用。
只能转换在一下场景生效
变量类型 | 说明 |
---|---|
var 本地变量 | 一般都会生效,除了局部委托变量 |
var 类属性 | 如果属性是私有的、内部的,或者检查是在声明属性的同一模块中进行的,那么可以使用智能转换。但是,智能转换不能用于开放属性或具有自定义 getter 的属性。 |
val 本地变量 | 如果变量在检查和使用之间没有被修改,没有被修改它的 lambda 捕获,也不是本地委托属性,那么就可以使用这个变量。 |
val 类属性 | 永远不会,因为变量可以在任何时候被其他代码修改。 |
不安全的强制转换
不安全的强制转换通常会报错,使用as
进行操作
fun main() {
val str: Any = "cast"
val s = str as String
val i = str as Int //报错 java.lang.ClassCastException: class java.lang.String cannot be cast to class java.lang.Integer
}
注意,不能使null
转换成String
类型,如果有null
风险,需要添加?
fun main() {
val str: Any? = null
val s1 = str as String?
val s2 = str as String // 报错 - java.lang.NullPointerException: null cannot be cast to non-null type kotlin.String
}
安全的强制转换
如果要避免异常,可以使用as?
,如果转换失败则返回null
fun main() {
val str: Any? = null
val s = str as? String
println(s) // null
}