Kotlin類型系統(tǒng)筆記

Kotlin語言基礎(chǔ)筆記

Kotlin流程控制語句筆記

Kotlin操作符重載與中綴表示法筆記

Kotlin擴展函數(shù)和擴展屬性筆記

Kotlin空指針安全(null-safety)筆記

Kotlin類型系統(tǒng)筆記

Kotlin面向?qū)ο缶幊坦P記

Kotlin委托(Delegation)筆記

Kotlin泛型型筆記

Kotlin函數(shù)式編程筆記

Kotlin與Java互操作筆記

Kotlin協(xié)程筆記

1. 根類型Any

Kotlin中所有的類都有一個共同的基類Any改鲫,如果類沒有申明繼承其他類的話,默認繼承的就是Any林束。我們測試一段代碼:

fun main(args: Array<String>) {
    val any = Any()
    println(any)   //打印java.lang.Object@49476842
    println(any::class)  //打印class kotlin.Any
    println(any::class.java)  //打印class java.lang.Object
}

上面輸出可以看到其實Kotlin中的Any就是對應Java中的java.lang.Object類型像棘。在Java 中Object類是所有引用類型的父類,但是不包括那些基本類型壶冒,int缕题,long,float等胖腾。而在Kotlin中所有的類型都是引用類型烟零,統(tǒng)一繼承父類Any。

注意胸嘁,如果你發(fā)現(xiàn)println(any::class)打印出這么一段Kotlin reflection is not available瓶摆,請在你的gradle.gradle文件中加入下面這段依賴compile "org.jetbrains.kotlin:kotlin-reflect:$kotlin_version"

Any的源碼如下:

Any

它只有三個方法性宏,equals群井,hashCode和toString。這三個方法跟Java中的意思是一樣的毫胜,唯一不同的是书斜,Any的equals在Kotlin中進行了操作符重載诬辈,所以大家可以使用==來進行值相等的比較。

2. 基本類型

在Java中有byte荐吉、int焙糟、short、long样屠、float穿撮、double、char痪欲、boolean這些基本類型悦穿,另外,void也可以算是一種基本類型业踢,它也有一個裝箱類Void(Koltin中也有類似的概念栗柒,Unit、Nothing)知举,Void不能new出來瞬沦。
在Kotlin中是真正的一切皆是對象。所有的類型都是引用類型雇锡。Kotlin中的基本類型的類圖如下:

基本類型

2.1 數(shù)字(Number)類型

Kotlin 提供了如下的內(nèi)置類型來表示數(shù)字(與 Java 很相近):

類型 寬度(Bit)
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

從上面的類結(jié)構(gòu)圖逛钻,我們可以看到這些內(nèi)置的數(shù)字類型,都繼承了Number和Comparable類锰提。Kotlin的數(shù)字類型跟Java的基本相同绣的,但是要注意的是Kotlin中數(shù)字沒有隱私轉(zhuǎn)化,也就是說Kotlin的Int不能自動轉(zhuǎn)換成Long欲账。另外:Kotlin中字符Char不是數(shù)字。Kotlin的這些內(nèi)部數(shù)字類型在運行時會自動轉(zhuǎn)換成Java的基本類型芭概。

數(shù)值常量字面值有以下幾種
  • 十進制:123
  • Long類型:123L
  • 十六進制:0x0F
  • 二進制:0b000011
  • Double類型:123.123赛不、123.123e10
  • Float類型:123.123f123.123F
  • 我們也可以使用下劃線來分隔數(shù)字:1_000_000罢洲、1234_5678_9012_3456L踢故、0xFF_EC_DE_5E0b11010010_01101001_10010100_10010010
顯示轉(zhuǎn)換

范圍較小的類型需要顯示轉(zhuǎn)換成較大的類型惹苗。


image.png

image.png

你需要顯示轉(zhuǎn)換類型殿较,如下代碼:

fun main(args: Array<String>) {
    val a: Int? = 1
    val g: Long? = a?.toLong()

    val b: Byte = 1
    val i: Int = b.toInt()
}

每個數(shù)字類型都繼承Number類,而Number中定義了一些方法用來方便的做顯示轉(zhuǎn)換桩蓉。


Number
操作符重載

有時候缺少隱式轉(zhuǎn)換也沒關(guān)系淋纲,例如Long類對+進行了重載。

public operator fun plus(other: Byte): Long
public operator fun plus(other: Short): Long
public operator fun plus(other: Int): Long
public operator fun plus(other: Long): Long
public operator fun plus(other: Float): Float
public operator fun plus(other: Double): Double

2.2 Char字符類型

字符用Char表示院究。他們不能直接用來當作數(shù)字洽瞬。

image.png

特殊字符可以用反斜杠轉(zhuǎn)義本涕,當然也支持Unicode轉(zhuǎn)義序列語法,例如:\uFF00伙窃。

2.3 String 字符串類型

索引運算符
fun main(args: Array<String>) {
    val s: String = "abc"
    println(s[2])  //打印c
}

查看源碼可以知道菩颖,s[i]會被翻譯成java.lang.String.charAt()

循環(huán)迭代字符串
fun main(args: Array<String>) {
    val s: String = "abc"
    for (c in s) {
        println(c)
    }
}
操作符+重載

字符串String類型重載了+操作符为障,作用對象是可以任意對象晦闰,包括空引用:

>>> "abc".plus(true)
abctrue
>>> "abc"+false
abcfalse
>>> "abc"+1
abc1
>>> "abc"+1.20
abc1.2
>>> "abc"+100L
abc100
>>> "abc"+"cdef"
abccdef
>>> "abc"+null
abcnull
>>> "abc"+'z'
abcz
>>> "abc"+arrayOf(1,2,3,4,5)
abc[Ljava.lang.Integer;@3d6f0054
字符串的值

使用兩個雙引號定義,其中可以包含一些轉(zhuǎn)義字符鳍怨。

val s: String = "Hello world, \n\n\n"

還可以使用三個雙引號(""")括起來呻右,里面可以包含任意字符。

    val s: String = """
        for (c in "abc")
            print(c)
        """

另外:在kotlin.text包下面的Indent.kt中定義了String類的擴展函數(shù)京景。我們可以使用trimMargin()trimIndent()來去除空格窿冯。
trimMargin()默認使用"|"來作為邊界字符。

fun main(args: Array<String>) {
    val text = """
     |理論是你知道是這樣确徙,但它卻不好用醒串。
     |實踐是它很好用,但你不知道是為什么鄙皇。
     |程序員將理論和實踐結(jié)合到一起:
     |既不好用芜赌,也不知道是為什么。
   """
    println(text.trimMargin())
}

輸出

理論是你知道是這樣伴逸,但它卻不好用缠沈。
實踐是它很好用,但你不知道是為什么错蝴。
程序員將理論和實踐結(jié)合到一起:
既不好用洲愤,也不知道是為什么。

trimIndent()則是把字符串行的左邊空白對其切割:

fun main(args: Array<String>) {
    val text = """
           hello
       world!
   """
    println(text.trimIndent())
}

輸出

     hello
world!
字符串模版

字符串中可以包含一些表達式顷锰,如下:

fun main(args: Array<String>) {
    val name = "Denny"
    val price = 100.5
    println("My name is $name")  //打印My name is Denny
    println("$name.length is ${name.length}")  //打印Denny.length is 5
    println("""the price is $$price""")  //打印the price is $100.5
}

2.4 Array 數(shù)組類型

class Array<T> private constructor() {
    val size: Int
    operator fun get(index: Int): T
    operator fun set(index: Int, value: T): Unit
    operator fun iterator(): Iterator<T>
    // ……
}

我們可以看到Array重載了[]操作符柬赐。
我們可以使用arrayOf()來創(chuàng)建一個數(shù)組,并給定數(shù)組中的初始值官紫。

fun main(args: Array<String>) {
    val a1 = arrayOf(1, 2, 3)
    println(a1::class)  //打印class kotlin.Array
    println(a1::class.java)  //打印class [Ljava.lang.Integer;

    val a2 = arrayOf(1, "s", null)
    println(a2::class)  //打印class kotlin.Array
    println(a2::class.java)  //打印class [Ljava.lang.Object;
}

我們可以使用arrayOfNulls()來創(chuàng)建一個指定大小肛宋,元素都為null的數(shù)組,在創(chuàng)建的時候我們必須指定其中元素的類型束世,要不然會報錯酝陈。

error

另外:Array類還有一個構(gòu)造函數(shù)。

public inline constructor(size: Int, init: (Int) -> T)

第一個參數(shù)是數(shù)組的大小毁涉,第二個參數(shù)是初始化函數(shù)類型的參數(shù)沉帮。比如:

fun main(args: Array<String>) {
    val a = Array(8, { i -> i + i })
    println(a.joinToString(prefix = "[", postfix = "]"))  //打印[0, 2, 4, 6, 8, 10, 12, 14]
}

Kotlin中也有無裝箱開銷的用來表示原生類型的數(shù)組。這些原生數(shù)組類型如下:

  • BooleanArray
  • ByteArray
  • CharArray
  • ShortArray
  • IntArray
  • LongArray
  • FloatArray
  • DoubleArray
  • BooleanArray
    這些類和Array沒有繼承關(guān)系,但是他們有同樣的函數(shù)和屬性遇西,他們也有相應的工廠方法:
/**
 * Returns an array containing the specified [Double] numbers.
 */
public fun doubleArrayOf(vararg elements: Double): DoubleArray

/**
 * Returns an array containing the specified [Float] numbers.
 */
public fun floatArrayOf(vararg elements: Float): FloatArray

/**
 * Returns an array containing the specified [Long] numbers.
 */
public fun longArrayOf(vararg elements: Long): LongArray

/**
 * Returns an array containing the specified [Int] numbers.
 */
public fun intArrayOf(vararg elements: Int): IntArray

/**
 * Returns an array containing the specified characters.
 */
public fun charArrayOf(vararg elements: Char): CharArray

/**
 * Returns an array containing the specified [Short] numbers.
 */
public fun shortArrayOf(vararg elements: Short): ShortArray

/**
 * Returns an array containing the specified [Byte] numbers.
 */
public fun byteArrayOf(vararg elements: Byte): ByteArray

/**
 * Returns an array containing the specified boolean values.
 */
public fun booleanArrayOf(vararg elements: Boolean): BooleanArray

3. 可空類型(Nullable Types)

Kotlin把可空性作為類型系統(tǒng)的一部分馅精,這樣編譯器可以在編譯過程中發(fā)現(xiàn)一些可能的錯誤,減少運行過程中拋出異常的可能性粱檀。
Kotlin的類型系統(tǒng)和Java相比洲敢,主要的區(qū)別就是Kotlin對可空類型的顯示支持。

3.1 Kotlin中的null

fun main(args: Array<String>) {
    println(null == null)  //打印true
    println(null != null)  //打印false
    println(null is Any)  //打印false
    println(null is Any?)  //打印true
}

與Java不同茄蚯,Kotlin中null與null是相等的压彭,null不是Any類型,但是是Any渗常?類型壮不。下面我們來看看Null到底是什么類型。

null

編譯器告訴我們null的類型是Nothing?皱碘。

3.2 可空性的實現(xiàn)原理

假如我們有這樣一個StringUtil.kt類询一。

package com.dengyin2000.kotlintest1
object StringUtil{
    fun testNullable1(x: String, y: String?): Int {
        return x.length
    }

    fun testNullable2(x: String, y: String?): Int? {
        return y?.length
    }

    fun testNullable3(x: String, y: String?): Int? {
        return y!!.length
    }
}

然后我們來看看上面的代碼對應生成的Java代碼是怎樣的。在Intellij IDEA中點擊"Tools" -> "Kotlin" -> "Show Kotlin Bytecode"癌椿。


bytecode

再在出來的界面上點擊"Decompile"健蕊。


decompile

最后就能看到最終生成的Java代碼,代碼如下:


finalcode

我們可以看到生成的Java代碼踢俄,不可為空變量都注解了@NotNull缩功,而可為空變量注解了@Nullable
在函數(shù)調(diào)用前都用kotlin.jvm.internal.Intrinsics. checkParameterIsNotNull方法檢查了不為空變量是否為空都办。

    public static void checkParameterIsNotNull(Object value, String paramName) {
        if (value == null) {
            throwParameterIsNullException(paramName);
        }
    }

而可空變量的安全調(diào)用符y?.length轉(zhuǎn)成Java的代碼如下:

y != null?Integer.valueOf(y.length()):null

可空變量的斷言調(diào)用y!!.length轉(zhuǎn)成的Java代碼如下:

      if (y == null) {
         Intrinsics.throwNpe();
      }

      return y.length();

3.3 可空類型層次體系

Any是非空類型的根嫡锌,Any?是可空類型的根,由于Any?是Any的根琳钉,所以Any?是Kotlin的類型層次結(jié)構(gòu)的最頂端势木。

層次結(jié)構(gòu)

fun main(args: Array<String>) {
    println(1 is Any)  //打印true
    println(1 is Any?)  //打印true
    println(null is Any)  //打印false
    println(null is Any?)  //打印true
    println(Any() is Any?)  //打印true
}

4. kotlin.Unit類型

Kotlin中的Unit類實現(xiàn)了跟Java中void一樣的功能,大多數(shù)情況下歌懒,我們并不需要顯示的返回Unit跟压,或者申明一個函數(shù)的返回類型為Unit。編譯器會推斷它歼培。

fun sayHello1() {
}

fun sayHello2() {
    return Unit
}

fun sayHello3(): Unit {
}

fun main(args: Array<String>) {
    println(sayHello1())  //打印kotlin.Unit
    println(sayHello2())  //打印kotlin.Unit
    println(sayHello3())  //打印kotlin.Unit
}

這三個函數(shù)其實是一樣的∪兹總之這個Unit并沒有什么特別之處躲庄,看看它的源碼:

package kotlin

/**
 * The type with only one value: the Unit object. This type corresponds to the `void` type in Java.
 */
public object Unit {
    override fun toString() = "kotlin.Unit"
}

跟其他的類型一樣, Unit的父類是Any钾虐,Unit?的父類是Any?噪窘。

Unit

5. kotlin.Nothing類型

Kotlin中沒有類似Java中的返回值為void的標記,在Java中效扫,返回void方法倔监,其返回值是無法被訪問到的直砂。void不是變量的類型,但是在Java的包裝類中Voidvoid的包裝類浩习,如果你想讓一個方法返回類型永遠是null的話静暂,可以寫成如下:

public Void voidDemo() {
    System.out.println("Hello,Void");
    return null;
}

這個Void就是Kotlin中的Nothing?。它的唯一可被訪問到的值也是null谱秽。
注意:UnitNothing的區(qū)別:Unit類型表達式計算結(jié)果返回的是Unit類型洽蛀,Nothing類型表示永遠不會返回結(jié)果(跟Java的void相同)。
throw關(guān)鍵字中斷表達式的計算疟赊,并拋出堆棧的功能郊供。所以,一個throw Exception的代碼就是返回Nothing的表達式近哟。

fun formatCell(value: Double): String =
    if (value.isNaN()) 
        throw IllegalArgumentException("$value is not a number")  // Nothing
    else 
        value.toString()

再比如驮审,Kotlin的標準庫的exitProcess函數(shù):

@file:kotlin.jvm.JvmName("ProcessKt")
@file:kotlin.jvm.JvmVersion
package kotlin.system

/**
 * Terminates the currently running Java Virtual Machine. The
 * argument serves as a status code; by convention, a nonzero status
 * code indicates abnormal termination.
 *
 * This method never returns normally.
 */
@kotlin.internal.InlineOnly
public inline fun exitProcess(status: Int): Nothing {
    System.exit(status)
    throw RuntimeException("System.exit returned normally, while it was supposed to halt JVM.")
}

Nothing?可以只包含一個值:null。


Nothing

6. 類型檢測與類型轉(zhuǎn)換

6.1 is運算符

Kotlin的is運算符跟Java中的instanceof是一樣的吉执,用來檢測某個對象是否某個類型或者父類的實例疯淫。其實我們之前已經(jīng)有用到is運算符了

當你使用is運算符時鼠证,類型會自動轉(zhuǎn)換峡竣,例如:

open class Animal{
    open fun eat(){
        println("animal eat")
    }
}

open class Dog : Animal() {
    fun run() {
        println("run")
    }
}
class Bird : Animal() {
    fun fly() {
        println("fly")
    }
}

class Fish : Animal() {
    fun swin() {
        println("swin")
    }
}

fun playAnimal(animal: Animal) {
    when (animal) {
        is Dog -> animal.run()  //自動類型轉(zhuǎn)換
        is Bird -> animal.fly()  //自動類型轉(zhuǎn)換
        is Fish -> animal.swin()  //自動類型轉(zhuǎn)換
    }
}

如果是在Java中,我們需要用instanceof判斷后然后再顯示類型轉(zhuǎn)換(Cast)量九。

6.2 as運算符

as運算符用于進行顯示類型轉(zhuǎn)換适掰,如果轉(zhuǎn)換的類型與指定的類型兼容,轉(zhuǎn)換就能成功荠列,如果類型不兼容类浪,使用as?就會返回null。

package com.dengyin2000.kotlintest1

open class Animal{
    open fun eat(){
        println("animal eat")
    }
}

open class Dog : Animal() {
    fun run() {
        println("run")
    }
}
class Bird : Animal() {
    fun fly() {
        println("fly")
    }
}

class Fish : Animal() {
    fun swin() {
        println("swin")
    }
}

fun main(args: Array<String>) {
    val animal = Animal()

    val dog1 = animal as? Dog
    println(dog1)  //打印null

    val dog = animal as Dog  //Exception in thread "main" java.lang.ClassCastException: com.dengyin2000.kotlintest1.Animal cannot be cast to com.dengyin2000.kotlintest1.Dog
}
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末肌似,一起剝皮案震驚了整個濱河市费就,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌川队,老刑警劉巖力细,帶你破解...
    沈念sama閱讀 217,542評論 6 504
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異固额,居然都是意外死亡眠蚂,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,822評論 3 394
  • 文/潘曉璐 我一進店門斗躏,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逝慧,“玉大人,你說我怎么就攤上這事〉殉迹” “怎么了云稚?”我有些...
    開封第一講書人閱讀 163,912評論 0 354
  • 文/不壞的土叔 我叫張陵,是天一觀的道長沈堡。 經(jīng)常有香客問我静陈,道長,這世上最難降的妖魔是什么踱蛀? 我笑而不...
    開封第一講書人閱讀 58,449評論 1 293
  • 正文 為了忘掉前任窿给,我火速辦了婚禮,結(jié)果婚禮上率拒,老公的妹妹穿的比我還像新娘崩泡。我一直安慰自己,他們只是感情好猬膨,可當我...
    茶點故事閱讀 67,500評論 6 392
  • 文/花漫 我一把揭開白布角撞。 她就那樣靜靜地躺著,像睡著了一般勃痴。 火紅的嫁衣襯著肌膚如雪谒所。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,370評論 1 302
  • 那天沛申,我揣著相機與錄音劣领,去河邊找鬼。 笑死铁材,一個胖子當著我的面吹牛尖淘,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播著觉,決...
    沈念sama閱讀 40,193評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼村生,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了饼丘?” 一聲冷哼從身側(cè)響起趁桃,我...
    開封第一講書人閱讀 39,074評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎肄鸽,沒想到半個月后卫病,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,505評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡典徘,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,722評論 3 335
  • 正文 我和宋清朗相戀三年忽肛,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片烂斋。...
    茶點故事閱讀 39,841評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出汛骂,到底是詐尸還是另有隱情罕模,我是刑警寧澤,帶...
    沈念sama閱讀 35,569評論 5 345
  • 正文 年R本政府宣布帘瞭,位于F島的核電站,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏挂绰。R本人自食惡果不足惜堤尾,卻給世界環(huán)境...
    茶點故事閱讀 41,168評論 3 328
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望媒殉。 院中可真熱鬧担敌,春花似錦、人聲如沸廷蓉。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,783評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽桃犬。三九已至刹悴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間攒暇,已是汗流浹背土匀。 一陣腳步聲響...
    開封第一講書人閱讀 32,918評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留形用,地道東北人就轧。 一個月前我還...
    沈念sama閱讀 47,962評論 2 370
  • 正文 我出身青樓,卻偏偏與公主長得像尾序,于是被迫代替她去往敵國和親钓丰。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 44,781評論 2 354

推薦閱讀更多精彩內(nèi)容