一起學習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
"""
注意以上程式碼的列印結果是存在前置的空格號的:
我們可以藉助與 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)
列印結果為:
原生字串和轉義字串內部都支援模板。
6.3、索引運算子s[i]
當我們需要對一個字串的某一位取值時,java中會用到:
"abc".charAt(i);
而在kotlin中,我們可以簡單的用索引運算子即可:
val s = "abc"
s[0]//結果為a
6.4、for迴圈迭代字串
for (s in "12345"){println(s)}
列印結果:
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)}
上述程式碼的列印結果為:
注意:在這裡kotlin編譯器自動將陣列升級為java.lang.Object型別了。
7.3、新建空陣列
除此之外在新建空陣列時,我們必須顯示地知名陣列元素的型別:
val b = arrayOfNulls(10)//錯誤
val b = arrayOfNulls<Int>(10)//正確
7.4、陣列轉換
注意:kotlin中陣列不是形變的,即我們不能將Array賦值給Array。