Kotlin 教程之「基礎(chǔ)類(lèi)型」

Kotlin 中择诈,我們可以調(diào)用任何變量的成員函數(shù)和屬性凡蚜,從這個(gè)角度來(lái)說(shuō),一切皆對(duì)象吭从。某些類(lèi)型可以有特殊的內(nèi)部表現(xiàn) - 例如,數(shù)字恶迈、字符和布爾型在運(yùn)行時(shí)可以表現(xiàn)為基礎(chǔ)類(lèi)型(primitive types)涩金,但是對(duì)用戶(hù)來(lái)說(shuō)谱醇,他們看上去就是是普通的類(lèi)。這一章節(jié)主要描述 Kotlin 的基本類(lèi)型:數(shù)字步做、字符副渴、布爾、數(shù)組和字符串全度。

數(shù)值

Kotlin 處理數(shù)字的方式與 Java 類(lèi)似煮剧,但不是完全一致。例如将鸵,數(shù)值沒(méi)有隱式的拓寬轉(zhuǎn)換(implicit widening conversions)勉盅,某些情況下,字面意思也會(huì)稍有不同顶掉。

Kotlin 提供了如下內(nèi)置類(lèi)型來(lái)表示數(shù)值(接近 Java):

類(lèi)型 位寬
Double 64
Float 32
Long 64
Int 32
Short 16
Byte 8

注意:字符不是一種數(shù)值草娜。

字面常量

整形值的字面常量有如下形式:

  • 十進(jìn)制:123
    • 長(zhǎng)整型用 L 做標(biāo)記:123L
  • 十六進(jìn)制:0x0F
  • 二進(jìn)制:0b00001011

注意:不支持八進(jìn)制。

浮點(diǎn)數(shù)也支持約定的標(biāo)記:

  • double 類(lèi)型:123.5痒筒,123.5e10
  • float 用 f 或者 F 標(biāo)記:123.5f

數(shù)值字面值中的下劃線(xiàn)(1.1開(kāi)始)

下劃線(xiàn)可以使數(shù)值常量更具可讀性:

val oneMillion = 1_000_000
val creditCardNumber = 1234_5678_9012_3456L
val socialSecurityNumber = 999_99_9999L
val hexBytes = 0xFF_EC_D5_5E
val bytes = 0b11010010_01101001_10010100_10010010

表現(xiàn)形式

Java 平臺(tái)會(huì)把數(shù)值作為 JVM 基礎(chǔ)類(lèi)型來(lái)物理存儲(chǔ)宰闰。除非是一個(gè)可為空的數(shù)值引用(例如 Int?)或者有泛型引入。如果是后者簿透,數(shù)值會(huì)裝箱移袍。

注意:裝箱后的數(shù)值不會(huì)保持 identity

val a: Int = 10000
print(a === a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA === anotherBoxedA) // !!!Prints 'false`!!!

但是仍然會(huì)有相等性:

val a: Int = 10000
print(a == a) // Prints 'true'
val boxedA: Int? = a
val anotherBoxedA: Int? = a
print(boxedA == anotherBoxedA) // Prints 'true'

顯示轉(zhuǎn)換

由于不同的表現(xiàn)形式,小類(lèi)型并非大類(lèi)型的子類(lèi)型老充。如果是的話(huà)葡盗,可能會(huì)帶來(lái)如下麻煩:

// Hypothetical code, does not actually compile:
val a: Int? = 1 // A boxed Int (java.lang.Integer)
val b: Long? = a // implicit conversion yields a boxed Long (java.long.Long)
print(a == b) // Surprise! This prints "false" as Long's equals() check for other part to be Long as well

所以,不只是身份(identity)蚂维,連相等性(equality)也會(huì)靜默丟失戳粒。

因此,小類(lèi)型不會(huì)隱式轉(zhuǎn)換成大類(lèi)型虫啥。這就意味著:不通過(guò)顯示轉(zhuǎn)換蔚约,我們無(wú)法把一個(gè) Byte 賦值給 Int

val b: Byte = 1 // OK, literals are checked statically
val i: Int = b // ERROR

通過(guò)顯示轉(zhuǎn)換可以“拓寬(widen)”數(shù)值涂籽。

val i: Int = b.toInt()  // OK: explicitly widened

每個(gè)數(shù)值類(lèi)型都支持如下轉(zhuǎn)換:

  • toByte(): Byte
  • toShort(): Short
  • toInt(): Int
  • toLong(): Long
  • toFloat(): Float
  • toDouble(): Double
  • toChar(): Char

缺少隱式轉(zhuǎn)換并不會(huì)引起注意苹祟,因?yàn)橥ㄟ^(guò)上下文可以推導(dǎo)出類(lèi)型,并且算術(shù)操作符也有支持類(lèi)型轉(zhuǎn)換的重載评雌,例如:

val l = 1L + 3 // Long + Int => Long

運(yùn)算

Kotlin 支持?jǐn)?shù)值的標(biāo)準(zhǔn)算術(shù)運(yùn)算树枫,這些運(yùn)算被聲明為相應(yīng)類(lèi)的成員(但是編譯器會(huì)把函數(shù)調(diào)用優(yōu)化成相應(yīng)的指令)。參考操作符重載景东。

位運(yùn)算操作符也沒(méi)有特殊之處砂轻,他們也只是支持中綴調(diào)用的命名函數(shù),例如:

val x = (1 shl 2) and 0x000FF000

如下是位運(yùn)算操作符的完整列表(只用于 IntLong):

  • shl(bits) - 有符號(hào)左移(Java 的 <<
  • shr(bits) - 有符號(hào)右移(Java 的 >>
  • ushr(bits) - 無(wú)符號(hào)右移(Java 的 >>>
  • and(bits) - 位的與運(yùn)算
  • or(bits) - 位的或運(yùn)算
  • xor(bits) - 位的異或運(yùn)算
  • inv(bits) - 位的非運(yùn)算

浮點(diǎn)數(shù)比較

本節(jié)所要討論的浮點(diǎn)數(shù)運(yùn)算符有:

  • 相等檢查:a == ba != b
  • 比較操作符:a < b斤吐,a > b搔涝,a <= b, a >=b
  • 范圍初始化和范圍檢查:a..b厨喂,x in a..bx !in a..b

當(dāng)操作數(shù) ab 靜態(tài)已知為類(lèi)型 FloatDouble庄呈,以及它們對(duì)應(yīng)的可空類(lèi)型(得出方式包括:聲明蜕煌、推斷或者智能轉(zhuǎn)換),數(shù)值的運(yùn)算以及它們形成的范圍(range)遵守 IEEE 754 制定的浮動(dòng)點(diǎn)數(shù)運(yùn)算規(guī)范诬留。

但是為了支持通用的使用場(chǎng)景以及提供完整的排序斜纪,當(dāng)操作數(shù)不是浮點(diǎn)數(shù)的靜態(tài)類(lèi)型(如 AnyComparable<...>文兑,類(lèi)型參數(shù))時(shí)盒刚,運(yùn)算操作會(huì)使用 FloatDoubleequalscompareTo 實(shí)現(xiàn),這會(huì)導(dǎo)致異與標(biāo)準(zhǔn)彩届,因此:

  • NaN 等于它自己
  • NaN 大與所有其他元素伪冰,包括 POSITIVE_INFINITY
  • -0.0 小于 0.0

字符

Char 表示字符,不能直接用作數(shù)值:

fun check(c: Char) {
    if (c == 1) { // ERROR: incompatible types
        // ...
    }
}

字符用單引號(hào)來(lái)表示:'1'樟蠕。特殊字符可以使用反斜杠來(lái)轉(zhuǎn)義贮聂。

特殊字符可以用反斜杠轉(zhuǎn)義。支持的轉(zhuǎn)義序列有:\t寨辩、\b吓懈、\n\r靡狞、\'耻警、\"\\甸怕、\$甘穿。如果要編譯其他字符,可以使用 Unicode 轉(zhuǎn)義序列語(yǔ)法:\uFF00梢杭。

我們可以顯示地把一個(gè)字符轉(zhuǎn)換成一個(gè) Int 數(shù)值:

fun decimalDigitValue(c: Char): Int {
    if (c !in '0'..'9')
        throw IllegalArgumentException("Out of range")
    return c.toInt() - '0'.toInt() // Explicit conversions to numbers
}

就像數(shù)值那樣温兼,字符的空引用也會(huì)自動(dòng)裝箱。裝箱操作不會(huì)保留字符的身份(identity)武契。

布爾型

Boolean 表示布爾型募判,有兩個(gè)值:truefalse

布爾的可空引用會(huì)自動(dòng)裝箱咒唆。

內(nèi)置操作符包括:

  • || - lazy disjunction
  • && - lazy conjunction
  • ! - negation

數(shù)組

Kotlin 用類(lèi) Array 來(lái)表示數(shù)組届垫,有 getset 函數(shù)(利用操作符重載的約定可轉(zhuǎn)換成 [] 操作),還有 size 屬性全释,除此之外還有其他有用的成員函數(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>
    // ...
}

使用庫(kù)函數(shù) arrayOf() 并傳入元素值可以創(chuàng)建一個(gè)數(shù)組:arrayOf(1, 2, 3) 創(chuàng)建了 [1, 2, 3]装处。另外,arrayOfNulls() 可以創(chuàng)建一個(gè)所有元素都是 null 的數(shù)組浸船。

另一種創(chuàng)建方式是調(diào)用 Array 的構(gòu)造函數(shù),傳入數(shù)組大小和一個(gè)根據(jù)下標(biāo)返回初始值的函數(shù):

// Creates an Array<String> with values ["0", "1", "4", "9", "16"]
val asc = Array(5, { i -> (i * i).toString() })

上面已經(jīng)說(shuō)過(guò),[] 操作等價(jià)于調(diào)用成員函數(shù) get()set()罗售。

注意:與 Java 不同伶棒,Kotlin 的數(shù)組是不可變的(invariant)。這就意味著 Kotlin 不允許我們把 Array<String> 賦給 Array<Any>项戴,這樣能避免運(yùn)行時(shí)的失斝伟铩(但是能用 Array<out Any>,可參考類(lèi)型映射)周叮。

Kotlin 也有特定的類(lèi)用于表示基礎(chǔ)類(lèi)型數(shù)組(沒(méi)有裝箱的開(kāi)銷(xiāo)):ByteArray辩撑、ShortArrayIntArray 等仿耽。這幾個(gè)類(lèi)和 Array 沒(méi)有直接的繼承關(guān)系合冀,但是他們有同樣的方法和屬性。每個(gè)類(lèi)型都有相應(yīng)的工廠(chǎng)函數(shù):

val x: IntArray = intArrayOf(1, 2, 3)
x[0] = x[1] + x[2]

字符串

字符串由 String 表示项贺。字符串是不可變的君躺。字符串的元素可通過(guò)下標(biāo)訪(fǎng)問(wèn):s[i]。字符串可通過(guò) for 循環(huán)遍歷:

for (c in str) {
    println(c)
}

字符串字面值

Kotlin 支持兩種類(lèi)型的字符串字面值:包含轉(zhuǎn)義字符的轉(zhuǎn)義字符串和包含換行和任意文本的純字符串开缎。轉(zhuǎn)義字符串跟 Java 類(lèi)似:

val s = "Hello, world\n"

轉(zhuǎn)義遵守約定俗成的方式(利用 \)棕叫。上面的字符那一章節(jié)已經(jīng)列出了所有支持的轉(zhuǎn)義序列。

純字符串通過(guò)三個(gè)引號(hào)(""")來(lái)界定奕删,它不會(huì)包含轉(zhuǎn)義而且能夠包含換行和任意字符:

val text = """
    for (c in "foo")
        print(c)
"""

可以通過(guò) trimMargin() 去除開(kāi)頭的空字符:

val text = """
    |Tell me and I forget
    |Teach me and I remember.
    |Involve me and I learn.
    |(Benjamin Franklin)
    """.trimMargin()

默認(rèn)情況下俺泣,| 用作 margin 前綴,但是也可以使用其他字符作為參數(shù)傳給 trimMargin完残,例如 trimMargin(">")伏钠。

字符串模板

字符串可以包含模板表達(dá)式,例如谨设,可被求值的代碼片段熟掂,求值結(jié)果可以連接到字符串中。模板表達(dá)式以美元符號(hào)($)開(kāi)始铝宵,由一個(gè)簡(jiǎn)單的名稱(chēng)組成:

val i = 10
val s = "i = $i" // evaluates to "i = 10"

或者是大括號(hào)內(nèi)的任意表達(dá)式:

val s = "abc"
val str = "$s.length is ${s.length}" // evaluates to "abc.length is 3"

模板可用于純字符串和轉(zhuǎn)義后的字符串內(nèi)打掘。如果要在純字符串(不支持轉(zhuǎn)義)中展示 $ 符號(hào),可以使用如下語(yǔ)法:

val price = """
${'$'}9.99
"""
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末鹏秋,一起剝皮案震驚了整個(gè)濱河市尊蚁,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌侣夷,老刑警劉巖横朋,帶你破解...
    沈念sama閱讀 216,470評(píng)論 6 501
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異百拓,居然都是意外死亡琴锭,警方通過(guò)查閱死者的電腦和手機(jī)晰甚,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,393評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén),熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)决帖,“玉大人厕九,你說(shuō)我怎么就攤上這事〉鼗兀” “怎么了扁远?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,577評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀(guān)的道長(zhǎng)刻像。 經(jīng)常有香客問(wèn)我畅买,道長(zhǎng),這世上最難降的妖魔是什么细睡? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,176評(píng)論 1 292
  • 正文 為了忘掉前任谷羞,我火速辦了婚禮,結(jié)果婚禮上溜徙,老公的妹妹穿的比我還像新娘湃缎。我一直安慰自己,他們只是感情好萌京,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,189評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布雁歌。 她就那樣靜靜地躺著,像睡著了一般知残。 火紅的嫁衣襯著肌膚如雪靠瞎。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 51,155評(píng)論 1 299
  • 那天求妹,我揣著相機(jī)與錄音乏盐,去河邊找鬼。 笑死制恍,一個(gè)胖子當(dāng)著我的面吹牛父能,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播净神,決...
    沈念sama閱讀 40,041評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼何吝,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了鹃唯?” 一聲冷哼從身側(cè)響起爱榕,我...
    開(kāi)封第一講書(shū)人閱讀 38,903評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎坡慌,沒(méi)想到半個(gè)月后黔酥,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,319評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,539評(píng)論 2 332
  • 正文 我和宋清朗相戀三年跪者,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了棵帽。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,703評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡渣玲,死狀恐怖逗概,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情忘衍,我是刑警寧澤仗谆,帶...
    沈念sama閱讀 35,417評(píng)論 5 343
  • 正文 年R本政府宣布,位于F島的核電站淑履,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏藻雪。R本人自食惡果不足惜秘噪,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,013評(píng)論 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望勉耀。 院中可真熱鬧指煎,春花似錦、人聲如沸便斥。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,664評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)枢纠。三九已至像街,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間晋渺,已是汗流浹背镰绎。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,818評(píng)論 1 269
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留木西,地道東北人畴栖。 一個(gè)月前我還...
    沈念sama閱讀 47,711評(píng)論 2 368
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像八千,于是被迫代替她去往敵國(guó)和親吗讶。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,601評(píng)論 2 353

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