Kotlin 之旅2 資料型別

小楠總發表於2017-12-18

###Kotlin的資料型別

####Boolean型別

通過下面的程式碼定義了一個Boolean的變數b:

val b: Boolean = true
複製程式碼

Boolean大部分情況下是相當於Java中的boolean,但是有時候會裝箱成Java的Boolean,但是這都是由編譯器自動決定的,我們不用去理會。(其他型別也如此類推)

####Number型別

Kotlin中的數值型別如下所示:

Number型別.png

注意的地方:

  • 可以使用Int.MAX_VALUE等求最值(如此類推)
  • 與Java一樣,當型別不明確的時候,可以加L、F來標識;可以使用科學計數法
  • 可以用二進位制等進位制來表示數值,如:可以用0b00000011表示Int型的3
  • 當數值不正確的時候,例如列印0/0的時候,就會輸出NaN(即Not A Number),NaN沒有比較的意義。

#####型別轉換

Java中,支援隱式型別轉換,例如:

int i = 1;
long l = i;
複製程式碼

Kotlin型別轉換的時候,不可以隱式轉換,必須顯式轉換,例如:

val i: Int = 1
val l: Long = 1L

fun main(args: Array<String>) {
    //錯誤
    l = i
    //正確
    l = i.toLong()
}
複製程式碼

#####Kotlin不區分裝箱和非裝箱型別

在Java中,我們經常需要進行裝箱和非裝箱,例如:

Integer i1 = new Integer(1);
int i2 = 1;
複製程式碼

但是,Kotlin不區分裝箱和非裝箱型別,編譯器會自動幫我們進行轉換。

####Char型別

Char型別對應的是Java中的Character,佔兩個位元組,表示一個16位的Unicode字元。

val c: Char = '0'
//注意:這裡並不是String
val c1: Char = '\u000f'
複製程式碼

字元使用單引號''括起來,可以是常見的字元、編碼(注意不是String)、轉義字元。

Kotlin的轉義字元如下:

Kotlin的轉義字元.png

####String型別

本質就是一串Char型別,用雙引號""

#####下面是字串的建立方式

val s1: String = "love"
val s2: String = String(charArrayOf('l', 'o', 'v', 'e'))

//獲取字串長度
//s1.length
複製程式碼

#####字串的比較(注意與Java對比)

//相當於Java的equals
println(s1 == s2)
//相當於Java的==
println(s1 === s2)
複製程式碼

#####字串模板

//Java中,拼接很麻煩
println("" + a + "+" + b + "=" + (a + b))
//Kotlin中,很方便。類似於PHP
println("$a+$b=${a + b}")
複製程式碼

######Tips:$符號可以通過轉義字元$進行輸出

#####原始字元

原始字元用三引號引起來,字元會原封不動的輸出:

    val i: Int = 10000

    val rawStr: String = """
我愛你

    $i

年

    """
    println(rawStr)
複製程式碼

####空型別安全

先來看看Java程式碼:

public static void main(String[] args) {
    System.out.println(getName().length());
}

public static String getName() {
    return null;
}
複製程式碼

如果getName()方法是別人的庫,而且沒有原始碼的話,編譯器根本就不知道這裡會不會為空,因此這裡會有空指標的隱患的。

下面是Kotlin的程式碼示例:

fun getName(): String {
    return null
}
複製程式碼

因此我們就不能返回null了,因此我們可以放心使用getName()的返回值:

fun main(args: Array<String>) {
    println(getName().length) 
}

fun getName(): String {
    return "str"
}
複製程式碼

#####判空的省略版本

你會發現,這樣寫根本就編譯不通過,如果我們確實需要返回null,那麼我們需要加上一個問號:

fun getName(): String? {
    return null
}

fun main(args: Array<String>) {

    val name = getName() ?: return

    //上面的寫法是相當於:
    //val name = getName()
    //if (name == null) {
    //    return
    //}

	//因為上面已經判斷過了,因此可以放心使用了
    println(name.length)
}
複製程式碼

#####如果我們確實程式碼不為null

val str: String? = "haha"
//如果我們在程式碼中已經確定不為空指標的話,可以告訴編譯器放心編譯
println(str!!.length)
複製程式碼

#####安全的呼叫,可以在物件為空的時候,返回null,而不會觸發空指標

val str: String? = null
//這種寫法也是可以的
println(str?.length)//實際上列印的是null
//相當於
//if (str == null) {
//    println(null)
//} else {
//    println(str.length)
//}
複製程式碼

####智慧型別轉換

Java中,如果對型別進行了判斷,還是需要進行轉換的:

Parent p = new Child();
if (p instanceof Child) {
    ((Child) p).say();
}
複製程式碼

Kotlin中,如果對型別進行了判斷,那麼不需要進行轉換:

val p: Parent = Child()
if (p is Child) {
    //如果Kotlin編譯器判斷到已經對型別進行了判斷
    //那麼可以直接呼叫了
    p.say()
}
複製程式碼

####安全型別轉換

val p: Parent = Parent()
//不安全的型別轉換,轉換失敗會報異常
val c1: Child? = p as Child
//安全的型別轉換,轉換失敗的時候,返回null
val c2: Child? = p as? Child
複製程式碼

####區間

Kotlin中區間都是ClosedRange的子類,常用的有:

  • IntRange
  • CharRange
  • LongRange
  • ComparableRange

下面先來看看ClosedRange的實現:

public interface ClosedRange<T: Comparable<T>> {
    /**
     * The minimum value in the range.
     */
    public val start: T

    /**
     * The maximum value in the range (inclusive).
     */
    public val endInclusive: T

    /**
     * Checks whether the specified [value] belongs to the range.
     */
    public operator fun contains(value: T): Boolean = value >= start && value <= endInclusive

    /**
     * Checks whether the range is empty.
     */
    public fun isEmpty(): Boolean = start > endInclusive
}
複製程式碼

示例程式碼:

fun main(args: Array<String>) {

    //[0,100]
    val r1: IntRange = 0..100
    //[0,101)相當於[0,100]
    val r2: IntRange = 0 until 101
    //空區間
    val r3: IntRange = 0..-1

    println(r1.start)
    println(r1.endInclusive)

    //是否包含
    println(r1.contains(50))
    println(50 in r2)//運算子過載的方式判斷

    println(r3.isEmpty())

    //迭代
    for (i in r1) {
        println("$i,")
    }
}
複製程式碼

關於運算子過載,可以先來看看,詳細的後面再說:

public operator fun contains(value: T): Boolean = value >= start && value <= endInclusive
複製程式碼

####陣列

示例程式碼:

//基本資料型別的陣列(注意是經過定製的,減去了裝箱以及拆箱的開銷)
val arr: IntArray = intArrayOf(1, 2, 3, 4, 5, 6, 7)
//沒有經過定製的陣列
val arr1: Array<Int> = arrayOf(1, 2, 3, 4, 5, 6, 7)
//物件陣列
val arrMan: Array<Man> = arrayOf(Man("李"), Man("張"), Man("吳"))

//大小
println(arr.size)

//操作某一個元素
println(arr[0])

//連線成字串,可以指定分隔符(預設是,)
println(arr.joinToString(","))

//擷取,注意傳入的是一個區間(注意,字串也支援這種操作)
arr.slice(1..2)

//遍歷
for (i in arr) {
    println(i)
}
複製程式碼

如果覺得我的文字對你有所幫助的話,歡迎關注我的公眾號:

公眾號:Android開發進階

我的群歡迎大家進來探討各種技術與非技術的話題,有興趣的朋友們加我私人微信huannan88,我拉你進群交(♂)流(♀)

相關文章