1. 程式人生 > >一起學習Kotlin——Kotlin中的基本資料型別

一起學習Kotlin——Kotlin中的基本資料型別

Kotlin中的基本資料型別

作為Google【官方指定的乾兒子】,Kotlin語言今年受到了越來越多的重視。無論是開發Android還是後臺程式,這門語言以後一定是大有可為。由於相關的文章很多,那我們不多介紹這門語言是怎麼來的。就讓我們慢慢來,一點一點的去品味Kotlin。

第一章,一起來看看這門語言的基本資料型別吧。

開始之前,我們需要明確一點:

kotlin是一門【強型別】、【靜態型別】、【支援隱式型別】的【顯式】型別語言。

PS:
1、強型別:強型別語言的編譯器引入了較多的型別檢查限制,因此在執行時不會發生未經明確(顯示轉換)型別轉換的型別轉換。常見的語言中,Java就是強型別語言,而JavaScript則是弱型別語言。
2、

靜態型別:根據型別檢查在編譯時期還是執行時期,我們把語言分為靜態型別以及動態型別。靜態語言是基於編譯器來確保語言型別的安全。
3、顯式型別:根據變數名是否需要顯式的給出宣告,我們可以將語言分為顯式型別以及隱式型別。kotlin是顯式型別的語言,與此同時又因為有【型別推斷】的作用所以可以看做是支援隱式型別。

一、簡述

1、var 與 val

kotlin中,var符號表示的事變數,可以多次重複賦值。
而val表示的是“常量”,但這並不是通俗意義上的常量。本質上val也是變數,但一次賦值之後,不能再次修改,只能作為【只讀變數】。

2、kotlin中的根型別:Any

kotlin中萬物皆物件,所有型別都是引用型別。所有的類都有一個超類:Any。
官方文件是這麼說的:

/**
* The root of the Kotlin class hierarchy. Every Kotlin class has [Any] as a superclass.
*/

這個類只有三個方法:

public open operator fun equals(other: Any?): Boolean
public open fun hashCode(): Int
public open fun toString(): String

如果類宣告中,沒有指明超類,則預設為Any。
kotlin中的Any對映為java中的java.lang.Object.

特別注意的一點:java中Object只是所有引用型別的超類,而基本型別int、long等不包含在內。而kotlin中,Any是一切的超類。

3、kotlin中的數字型別

3.1、常識介紹

kotlin中常見的數字型別分為以下6種:

方法名 轉換型別 補充
Byte 8位 1位元組
Short 16位 2位元組
Int 32位 4位元組
Long 64位 8位元組
Float 32位 4位元組
Double 64位 8位元組

根據名稱可以看出基本和java中的相關定義相近。
kotlin支援二進位制、十進位制、十六進位制;

但【不】支援八進位制

與此同時,kotlin在數值型別的表示方式上也支援下劃線,如:
val Million = 1000_000_000
val tmp = 123_456_789L
val demo = 0xDD_FF_EE

kotlin中的數字型別與java很是相近,但有一點不同:

kotlin沒有java語言的隱式變換(如byte->short->int->long 等)。

因此,java中的如下程式碼,在kotlin中是無法編譯的:

short a = 1;
int b = a;

當然,在kotlin中應該這樣描述:

val a : Int = 1
val b : Long = a

上述程式碼同樣是無法通過編譯的!

因此,遇到型別轉換我們就應該考慮一下【顯式轉換】:
java中,我們一般會這樣進行數值型別的顯式轉換:

int a = 1;
...
Long tmp = (long)a;

而kotlin中,我們可以這樣:

val a : Int = 1
val b : a.toLong()

相關的方法彙總如下:

方法名 轉換型別
toByte() Byte
toShort() Short
toInt() Int
toLong() Long
toFloat() Float
toDouble() Double
toChar() Char

這裡需要注意一點的是:

與java不同,kotlin中Char型別僅僅表示字元,不能再被直接當做數字。 因此,Char型別的變數必須在單引號之間表示:’變數’。(CSDN部落格這裡顯示有誤。。。)

一段簡單的java程式碼如下:

char a = 'c';
System.out.println(a+1);

此時列印的結果為【數字】100。
而作為對比,在kotlin中:

val a : Char = 'c'
println(a+1)

上述程式碼的列印結果為【字元】d

因此我們要明確:Kotlin中 Char型別由於不是直接當數值用,所以最後返回依舊是Char型。

3.2、一些需要注意的點

3.2.1、== 與 ===

kotlin中並沒有單純的數值,在我們定義每一個數值的時候,kotlin編譯器都在默默的為我們將定義的數值封裝成一個物件,以最大限度的解決空指標異常的問題。因此kotlin中數值的比較除了我們常見的 == 號之外還多了 === 。
當然,根據面向物件的定義也可以快速的瞭解:

符號名 作用 否定形式
== 【結構相等】比較兩個具體的【數值的大小】是否相同 !=
=== 【引用相等】比較兩個物件【在記憶體的儲存地址】是否相同 !==

ps:
編譯器中,== 等同於equal()方法。

舉個栗子來看:

fun main(args: Array<String>){
    val a : Int = 10
    println(a === a) //此處返回的值為true
    val b : Int = a
    println(a === b) //此處返回的值為true,因為賦值操作是記憶體地址賦值,而記憶體地址相同,其中的數字值自然相同
    println(a == b) //此處返回的值為true,原因同上

}

【☆☆☆】考慮到裝箱問題:數字裝箱不保留【同一性】,但保留數值的【相等性】。

    val a: Int = 200
    println(a === a) //此處返回的值為true
    val b :Int ? = a
    println(a === b) //此處返回的值為false,因為這是兩個物件,記憶體地址不相同
    println(a == b) //此處返回的值為true,數值相同

當然還有一個特殊情況,考慮到JVM虛擬機器的常量池特性:

val a: Int = 20
    println(a === a) //此處返回的值為true
    val b :Int ? = 20
    println(a === b) //此處返回的值為true
    println(a == b) //此處返回的值為true,數值相同

PS:
【1】JVM虛擬機器中維護著有符號整形常量池(-128,127),在這個範圍裡的數值都會直接使用常量池的記憶體地址,所以這個範圍內的數值裝箱後比較記憶體地址依舊是相等的。(常量池主要用於存放兩大類常量:字面量(Literal)和符號引用量(Symbolic References))
【2】kotlin中,?表示這個物件可能為空。因此這一句“val b :Int ? = a”
表示的意思除了普通的數字賦值外,還多了一層含義:如果被賦值物件為空,則開闢記憶體建立新的物件。

3.2.2、移位操作

在java中,移位操作的表示非常簡潔,直接用符號即可表示:

符號名稱 作用
<< 左移位操作
*>> 右移位操作(此處*為顯示效果)
*>>> 無符號右移位

而在kotlin中,則沒有這些簡單的符號表示,取而代之的是相應的移位操作方法:

符號名稱 作用
shl(bits) 左移位
shr(bits) 右移位
ushr(bits) 無符號右移位
and(bits) 與操作
or(bits) 或操作
xor(bits) 異或操作
inv() 反向操作
3.2.3、運算子 + 的過載

先來看一段程式碼:

val a = 10L + 1

很明顯,上述程式碼中,+ 左右兩個數分別為Long型別與Int型別。
那麼問題來了,我們前面說過,kotlin中並不支援數字型別的隱式轉換,而且上面表示式中的數字1並沒有顯示拓寬為Long型別,為何卻準確無誤呢???
答案很簡答,那就是kotlin中對於符號“+”的過載。
符號過載

看一看到,原始碼中有很多過載的方法。
當我們執行:val a = 10L + 1
實質上是:
val a = 10L.plus(1)

值得注意的一點是:XX.plus()方法中傳入的形參只能為數值型別!

4、kotlin中的字元型別

kotlin中的基本字元為Char型別,相關的知識點我們已經在前文討論過。

5、kotlin中的布林型別

布林用 Boolean 型別表示,它有兩個值:true 和 false。
若需要可空引用布林會被裝箱。

6、kotlin中的字串型別

kotlin中字串是String型別。
與java類似,kotlin中的String同樣是由final修飾的,即不可被繼承。我們一起來看一些新的特性。

6.1、支援多行字串

val string = """
            line 1
            line 2
            lin3 4
            """

注意以上程式碼的列印結果是存在前置的空格號的:
列印結果1

我們可以藉助與 trimMargin() 發放做到去除掉每行的前置空格。

val string = """
            |line 1
            |line 2
            |lin3 4
            """.trimMargin("|")

這裡有一點需要注意:trimMargin()方法需要傳入一個String型別的引數作為刪除前置空格並進行每行分割的標誌Flag,我們在這裡選用了”|”。

6.2、支援字串模板

在kotlin中,字串可以包含字串模板用來表示前面用的到的一段程式碼。kotlin中規定,所有的字串模板必須以美元符號”$”開頭。

 val a = "temp"
 val q = "$a.length():"
 println(q+a.length)

列印結果為:
列印結果2

原生字串和轉義字串內部都支援模板。

6.3、索引運算子s[i]

當我們需要對一個字串的某一位取值時,java中會用到:

"abc".charAt(i);

而在kotlin中,我們可以簡單的用索引運算子即可:

val s = "abc"
s[0]//結果為a

6.4、for迴圈迭代字串

    for (s in "12345"){println(s)}

列印結果:
列印結果3

7、kotlin中的陣列型別

7.1、生成陣列

kotlin中的陣列不是new出來的而是用了別的表示方法:
【1】fun_1

    val a = arrayOf(1,2,3) //1,2,3

【2】fun_2 工廠函式

    val b = Array(3, { i -> (i * 2) })//0,2,4

7.2、陣列的多型別表示

kotlin中的陣列支援多型別:

    val arr = arrayOf(1,2,true,"abc")
    for(c in arr){println(c)}

上述程式碼的列印結果為:
列印結果12
注意:在這裡kotlin編譯器自動將陣列升級為java.lang.Object型別了。
列印結果123

7.3、新建空陣列

除此之外在新建空陣列時,我們必須顯示地知名陣列元素的型別:

    val b = arrayOfNulls(10)//錯誤
    val b = arrayOfNulls<Int>(10)//正確

7.4、陣列轉換

注意:kotlin中陣列不是形變的,即我們不能將Array賦值給Array。