Kotlin系列之基本類型

今天一塊兒來看看kotlin中的基本類型,包括基本的數據類型和其餘一些特殊的與Java不一樣的類型。java

基本數據類型

在Java中數據類型被分爲基本數據類型和引用數據類型。在kotlin中全部的數據類型都是引用數據類型。與Java中的數據類型對應,kotlin中的數據類型有以下幾種:bash

數據類型 java中的類型 kotlin中的類型
整數 byte short int long Byte Short Int Long
浮點數 float double Float Double
字符 char Char
布爾 boolean Boolean

固然上面沒有列出Java對應的包裝類型。你會發現kotlin中的類型就是Java中的類型的首字母大寫,更像是Java中的包裝類型。ide

在kotlin中不區分基本數據類型和包裝類型,它永遠都只有一種類型。也就是在kotlin程序中,全部的類型都是對象類型,這樣看起來kotlin是一門比Java還更純粹的面嚮對象語言。函數

koltin之因此這樣設計,是能夠容許咱們能夠對數字類型的值直接調用方法,就像下面這樣:oop

fun main(args: Array<String>) {
    12.toString()
}
複製代碼

這在Java中是無法作到的。性能

可是咱們都知道,Java中的包裝類型是會損耗必定的性能的,那kotlin中的全部類型都是對象類型,會不會影響從程序性能呢?ui

咱們都知道kotlin程序最終是被編譯成class文件在JVM上運行,因此,儘管咱們在kotlin程序中使用的是對象類型,可是在編譯時kotlin會盡量編譯成Java中的基本數據類型,使程序運行更加高效。spa

下面咱們寫個簡單的程序驗證一下,有以下的kotlin函數,它被寫在Main.kt這個文件中,它的是Int:設計

fun test(num: Int){
   //...
}
複製代碼

咱們在IDEA裏面找到編譯後的class文件,使用下面的命令進行反編譯:code

javap -c MainKt
複製代碼

獲得下面的結果:

Compiled from "Main.kt"
public final class MainKt {
  public static final void test(int);
}
複製代碼

你會看到從class文件反編譯出的代碼中函數的參數已經變成了int類型。

下面的兩種狀況下kotlin不會將數據類型編譯成Java的基本數據類型。

1.泛型類

在Java中,受限於Java實現泛型的方式,JVM不支持將基本數據類型做爲泛型的類型參數,泛型集合中是不能存儲基本數據類型的,咱們是不可能寫出List<int>這樣的程序的集合的,咱們只能寫出List<Integer>這樣的代碼。

因爲kotlin代碼最終也是被編譯成class文件跑在JVM上,因此在kotlin中,做爲泛型的類型參數,kotlin中的類型會被編譯成包裝類型。

你們也可使用上面掩演示過的反編譯class文件的方式進行驗證。

2.可空的基本數據類型

還有一種狀況是可空的數據類型,在kotlin中也會被編譯成對應的包裝類型,這個其實很好理解,由於可空類型是要被容許存儲null值的,而基本數據類型是無法存儲null值的。

就像下面的代碼,在kotlin中會被編譯成對應的包裝類型:

fun test(num1: Int?, num2: Int?): Boolean{
    if (num1 == null || num2 == null){
        return false
    }
    return num1 > num2
}
複製代碼

上面的函數的兩個參數都會被編譯成Interger類型,可是函數返回值Boolean會被編譯爲bolean類型,下面是反編譯class文件後的內容,只給出了函數簽名相關的編譯結果:

Compiled from "Main.kt"
public final class MainKt {
  public static final boolean test(java.lang.Integer, java.lang.Integer);
}
複製代碼

同時你還應該注意到,由於是可空類型,兩個Int值在比較以前必須先判空,kotlin才運行以後的比較運算。

數據類型轉換函數

在Java中,一些數據類型是能夠自動像另外一些數據類型轉化的。好比當將一個int類型的變量賦值給long類型的變量時,就會自動發生轉化。

可是在kotlin中,是不容許這種自動轉化的。kotlin爲每一種數據類型都提供了轉化函數。當你將一種數據類型賦值給另外一種數據類型的變量時,必須顯式調用轉換函數,就像下面的代碼那樣:

fun main(args: Array<String>) {
    val intNum: Int = 13
    val longNum: Long = intNum.toLong()
    val intNum2: Int = longNum.toInt()
}
複製代碼

不管是從大範圍的數轉換爲小範圍的數,仍是小範圍的數轉換爲大範圍的數,都必須顯式調用轉換函數,當將一個大範圍的數轉換爲小範圍的數時會發生截斷,這種狀況跟咱們java中強行將一個大範圍的數轉換爲一個小範圍的數的處理方法是一致的。

Any類型

在kotlin中,Any類型是全部非空類型的根類型,相應的Any?類型是全部可空類型的根類型。Any類型至關於Java中的Object類型。

在與Java進行互操做時,Java中的Object類型會被當成kotlin中的Any類型。前面幾節的內容也提到了平臺類型,其實準確來講,Java中的Object類型做爲方法返回值或者是方法參數,在Kotlin中實際上是被看成平臺類型,也就是能夠看成可空類型,也能夠看成非空類型。除非他們被@Nullable或者是@NotNull這些註解修飾,纔會在kotlin中肯定爲具體的類型。

相應的kotlin中的Any類型在底層被編譯爲Java的Object類型。以下面的簡單的方法:

fun get(num: Any){

}
複製代碼

被反編譯後的方法簽名以下:

public static final void get(java.lang.Object);
複製代碼

Unit類型

在kotlin中,Unit類型至關於Java中的void,可是又不只僅是void。先說說第一種,至關於Java中的void,咱們看下面這個方法的定義:

fun after(): Unit{
    println(".....")
}
複製代碼

固然上面的代碼Unit是能夠省略的,這裏寫出來就是給你們看看它的第一種用法,咱們以前所寫的沒有返回值的函數,其實返回值都是Unit,只是他們都被省略了而已。

第二種狀況,Unit在kotlin中是一種類型,好比String也是一種類型。可是比較特殊的是,在kotlin中只有一個值是Unit類型,它也叫Unit類型,是否是有點繞,看下面的代碼:

val str1: String = "str1"
val  str2: String = "str2"
複製代碼

好比上面的代碼中,」str1「和「str2」這兩個字符串值都是String類型的,可是在kotlin中Unit類型的值只有一個,它叫Unit,看下面的代碼:

val x: Unit = Unit
複製代碼

上面x是Unit類型,你無法給它賦值其它值,只能賦值爲Unit。 那kotlin中爲何要這麼作呢?實際上是爲了實現一種優雅的泛型參數的處理。

咱們假設一種場景,咱們想定義一個接口,它裏面的一個函數的返回值返回一個泛型參數,咱們先看下面Java的實現方式:

//接口定義
public interface IHandler<T> {
    public T getSomething();
}

//接口實現1,方法返回String類型
public class Handler1 implements IHandler<String> {

    @Override
    public String getSomething() {
        String str = "";
        return str;
    }
}

//接口實現2,方法返回Void類型
public class Handler2 implements IHandler<Void> {

    @Override
    public Void getSomething() {
        return null;
    }
}
複製代碼

上面,咱們經過傳入不一樣的泛型參數,來實現函數返回不一樣的返回值,可是咱們看第二種接口實現,咱們想讓函數返回void,咱們必須使用Void類型,注意這是個不可實例化的對象類型,所以咱們必須在函數末尾寫上return null,這就讓代碼不夠優雅。若是咱們想讓函數返回void類型,那麼咱們就必須爲返回void這種特殊的狀況從新定義一個和原來接口同樣的接口,只是函數的返回值寫死爲void,好比下面這樣:

public interface IHandler2 {
    void getSomething();
}
複製代碼

那咱們看看咱們在kotlin中如何優雅地實現上面的接口:

class KtHandler: IHandler<Unit>{
    override fun getSomething() {
        
    }
}
複製代碼

看看上面的代碼,若是咱們將其補充完整是下面這樣:

class KtHandler: IHandler<Unit>{
    override fun getSomething(): Unit{
        return Unit
    }
}
複製代碼

可是因爲一個方法的返回值爲Unit是能夠省略的,同時,在一個沒有返回值的方法的最後一行,kotlin會隱式返回Unit,因此就變成了咱們前面看到的那樣。也沒有多餘的return null,也不須要爲沒有返回值的函數這種特殊狀況單獨處理,kotlin很好地兼容了這兩種狀況,是否是超級優雅。

Nothing類型

Nothing是kotlin中一種特殊的類型,它只能做爲函數返回值,或者做爲泛型函數的類型參數,它表示一個函數永遠不會正常結束。什麼意思呢?好比一個無限循環的函數就能夠聲明返回值爲Nothing,或者說一個函數必定會拋出異常,那他們的返回值就能夠聲明爲Noting,就像下面這樣:

fun loop(str: String): Nothing{
    while (true){
        
    }
}

fun fail(str: String): Nothing{
    throw IllegalArgumentException(str)
}
複製代碼

寫在最後

這一節咱們主要說了kotlin中的一些基本類型,一些類型與Java有些類似,也有一些是新增的類型,可是爲了良好的互操做性,基本在Java都有對應的類型,瞭解了這些類型,相信會讓咱們寫出的代碼更加優雅合理。

相關文章
相關標籤/搜索