美文网首页Kotlin
类型检测与类型转换:"is" 与 "as"

类型检测与类型转换:"is" 与 "as"

作者: 码农修行之路 | 来源:发表于2020-11-18 17:33 被阅读0次

    "is" 与 "as"

    "is" 操作符 代表对象是否是该指定类型
    "!is" 操作符 代表对象是否不是该指定的类型
    例如:

    fun main() {
        val str: Any = "小黄";
        // 变量str是Any类型 通过is智能转换为String
        if (str is String) {
            println("是String子类型")
        } else {
            println("非String子类型")
        }
        // 或者
        if (str !is Int) {
            println("不是Int类型")
        } else {
            println("是Int类型")
        }
    }
    
    • 相当于Java中关键字 instanceof
    if(str instanceof String ) {
        Log.i("test"," 是其子类 ");
    }
    

    智能转换 应用于while循环 when表达式:

    when (str) {
        is String -> println("是字符串类型")
        is Int -> println("是Int类型")
        is IntArray -> println("是Int数组类型")
        else -> println("其它未检测的类型")
    }
    

    智能转换规则:

    • 当编译器不能保证变量在检测和使用之间不可改变时,智能转换不能用
    1. val ->局部变量 可以 局部委托属性 不可
    2. val ->属性 如果属性是private或internal 再或者该检测在声明属性的同一模块中执行 可以 open的属性或具有自定义getter的属性 不可
    3. var ->局部变量 如果变量在检测和只用之间没有修改 没有在会修改它的lambda表达式中捕获,并且不是局部委托属性 可以
    4. var ->属性 绝不可能(因为该变量随时可以被其它代码修改)

    "不安全的"转换操作符

    • 如果遇到转换不可能的,转换操作符会抛出异常 因此称之为不安全的
    fun main() {
        val y: String? = null;
        // 异常 java.lang.NullPointerException: null cannot be cast to non-null type kotlin.String
        val x: String = y as String 
    }
    
    • null 不能转换为 String类型 String类型不是可空类型 上述示例标明 y 为空 y as String 就会抛出NPE,为了让代码用于可空值,可以在类型转换的右侧使用可空类型 ? 例如:
    fun main() {
        val y: String? = null;
        // 异常 java.lang.NullPointerException: null cannot be cast to non-null type kotlin.String
        val x: String? = y as String?
    }
    

    "安全的"(可空)转换操作符

    fun main() {
        //val y1: Int? = null;
        val y1: Int = 0;
        // java.lang.ClassCastException: java.lang.Integer cannot be cast to java.lang.String
        //val x1: String = y1 as String
        // 使用安全转换操作符 可以处理类型转换异常问题
        val x1: String? = y1 as? String
        println(x1)
    }
    
    • 尽管事实上 as? 的右边是一个非空类型的 String 但是其转换的结果是可空的 也可以在类型转换不同时 返回 null

    类型擦除

    KT在编译的时确保涉及泛型操作的类型安全性,而在运行时,泛型类型的实例并未带有关于它们实际类型参数的信息 例如:List<Foo> 会被擦除为 List<*> 通常,在运行时无法检测一个实例是否属于带有某个类型参数的泛型类型
    为此 编译器会禁止由于类型擦除而无法执行的is检测 例如 ints is List<Int> 或者 list is T(类型参数) 当然,可以对一个实例检测星投影的类型:

    fun main() {
        val list = listOf(22, 33, 44, 55)
        if (list is List<*>) {
            list.forEach {
                println(it)
            }
        }
    
        val body1 = Body("小黄")
        val body2 = Body("小杨")
        val body3 = Body("小王")
        var listBody = listOf(body1, body2, body3)
    
        if (listBody is List<*>) {
            listBody.forEach {
                println(it)
            }
        }
    }
    data class Body(val name: String)
    
    • 当已经让一个实例的类型参数(在编译期)静态检测 就可以对涉及非泛型部分做is检测或者类型转换(as)
    fun main() {
        val list1 = arrayListOf("小黄", "小李", "小朱")
        handlerStrings(list1);
        val listA = arrList as List<String>
        listA.forEachIndexed { index, value ->
            println(" list $index $value ")
        }
    }
    fun handlerStrings(arrList: ArrayList<String>) {
        if (arrList is List<String>) {
            // arrList 会智能转换为 List<String>
            arrList.forEach {
                println(it)
            }
        }
    }
    

    执行结果:
    arrayList 0 小黄
    arrayList 1 小李
    arrayList 2 小朱
    list 0 小黄
    list 1 小李
    list 2 小朱

    相关文章

      网友评论

        本文标题:类型检测与类型转换:"is" 与 "as"

        本文链接:https://www.haomeiwen.com/subject/ctuciktx.html