Kotlin 空類型安全與智能類型轉換

1、前言

<font face= 黑體>在 Kotlin 中的類與接口 中咱們已經講了 Kotlin 的 接口擴展方法,今天咱們來說 Kotlin 中的 空類型安全智能類型轉換java

2、Kotlin 空類型安全

2.一、空類型安全概念

<font face= 黑體>Java 語言中是沒有空類型安全這一律唸的,因此寫 Java 代碼常常會出現空指針異常,可是 Kotlin 致力於消除空引用所帶來的危險,因此就有了空類型安全概念。git

<font face= 黑體>下面這段代碼在 Kotlin 中是沒法編譯經過的,由於 Kotlin 的 String 是不能接受空值的,因此這個賦值操做是不被容許的。github

var nonNull: String = "Hello"
nonNull = null  // 不可空類型,不能賦值爲 null
// 訪問長度的話,不須要空判斷
val length = nonNull.length

<font face= 黑體>IDE 報錯以下所示:
在這裏插入圖片描述segmentfault

<font face= 黑體>可是若是咱們非得定義一個空值,也是有辦法的,Kotlin 爲了 100% 兼容 Java,必須得實現接收空值,因此要接收空值能夠在定義的時候加一個 ?。安全

<font face= 黑體>可是這個時候這個變量就多是空值,因此訪問的時候就會比較嚴格,好比下面代碼中的 nullable.length 就會報錯,由於可能觸發空指針異常。函數

var nullable: String? = "Hello"
nullable = null  // 可空類型,編譯經過
val length = nullable.length // 可能觸發空指針,編譯保報錯

<font face= 黑體>IDE 報錯以下所示:
在這裏插入圖片描述
<font face= 黑體>這個時候咱們想 nullable.length 不報錯能夠:this

  1. <font face= 黑體>當咱們肯定 nullable 不可能爲空的時候,能夠將 nullable 強轉爲不可空類型,以下所示:spa

    var nullable: String? = "Hello"
    // 不會報錯了(本身已經知道了,這個 nullable 不可能爲空)
    val length = nullable!!.length
  2. <font face= 黑體>若是咱們不肯定 nullable 是否爲空的時候,能夠用 ?. 來實現安全訪問,以下所示:線程

    var nullable: String? = "Hello"
    // 這種狀況下若是 nullable 爲空的話,那麼返回的 length 也是空
    val length = nullable?.length
    // 這時候 length 的類型不是 Int,而是 Int?,因此能夠寫成下面這樣
    val length: Int? = nullable?.length
    // 若是你想 length 的類型是 Int 的話,能夠加個默認值,寫成下面這樣
    val length: Int = nullable?.length ?: 0  // 若是 nullable?.length 爲空, 就返回0

2.二、空類型的繼承關係

<font face= 黑體>咱們知道 Int 是 Number 的子類,因此經過下面的代碼咱們就能夠知道 String 應該是 String? 的子類。
var a: Int = 2
var b: Number = 10.0

a = b // Type mismatch,報錯
b = a // OK

var x: String = "Hello"
var y: String? = "World"

x = y // Type mismatch,報錯
y = x // OK

2.三、Kotlin 空類型安全回顧

空類型安全小結

3、Kotlin 智能類型轉換

3.一、智能類型轉換例子

<font face= 黑體>例子1:指針

<font face= 黑體>咱們先來寫一個 Java 的類型轉換:

// 定義一個接口
public interface Kotliner {
}
// 定義一個類 Person 實現 Kotliner 接口
public class Person implements Kotliner {
    public final String name;
    public final int age;

    public Person(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public static void main(String[] args) {
        // 用子類的實例賦值給接口的引用
        Kotliner kotliner = new Person("Test", 20);
        // 這裏已經判斷了是否是 Person,可是下面仍是要強制類型轉換
        if (kotliner instanceof Person) {
            System.out.println(kotliner.name);  // 這樣寫報錯
            System.out.println(((Person) kotliner).name);  // 正確寫法
        }
    }
}

<font face= 黑體>一樣的代碼在 Kotlin 中就能夠實現智能類型轉換,不須要強制類型轉換:

val kotliner: Kotliner = Person("Test", 20)
if (kotliner is Person) {
    println((kotliner as Person).name)  // 不須要強轉,能夠智能轉換,因此下面的寫法就能夠了
    println(kotliner.name)
}

<font face= 黑體>例子2:

<font face= 黑體>下面這段代碼定義了一個 value, 類型是 String?,if 判斷其不爲空,因此在 if 判斷這個括號裏面,value 的類型會被智能轉換成 String,固然出了括號,value 的類型就又是 String? 了。
var value: String? = null
value = "Test"
if (value != null) {
    // value: String?  ==>  String
    println(value.length)
}
// value: String?
...

3.二、不支持智能類型轉換的狀況

<font face= 黑體>下面這種狀況就不支持智能類型轉換,由於這個公共變量不少地方均可以訪問,因此咱們在判斷不爲空以後,有可能別的線程又把 tag 改爲了空,因此這種狀況智能類型轉換就失效了。
// 在 main 函數以外定義一個公共變量
var tag: String? = null

fun main() {
    if(tag != null) {
        // 有可能被改爲空
        println(tag.length)  // 報錯,不支持智能類型轉換
    }
}

3.三、幾個建議

  • <font face= 黑體>儘量使用 val 來聲明不可變引用,讓程序的含義更加清晰肯定;
  • <font face= 黑體>儘量減小函數對外部變量的訪問;
  • <font face= 黑體>必要的時候曾建立局部變量指向外部變量,避免因它變化引發程序錯誤。

3.四、Kotlin 智能類型轉換

智能類型轉換小結

4、小結

<font face= 黑體>本篇博客主要講了 Kotlin 中的空類型安全智能類型轉換,下一節咱們講 Kotin 中的表達式

5、源碼

源碼 已上傳至 github,有須要能夠直接下載。

相關文章
相關標籤/搜索