kotlin 基本型態 包括:Byte、Short、Int、Long、Float、Double、Char與Boolean
但請注意 String 並不是
當我們宣告一個變數時,我們可以指定他的型態
var a : Cat = Cat ()
但Kotlin 也有自動判別的功能,例如下面編譯器就會自動指定一個型態給變數
var a = Cat ()
型態對編譯器很重要,打個比方,他不允許把一個 Dog 指派給 一個型態為 Cat 的變數,因為 Dog 不能用來執行 Cat 的行為。
為了防止導致bug 編譯器需要知到變數的型態。
我們可以變數指派給另一個變數,但必須確定兩者型態是相同的。
運作說明如下:
var a = Cat ()
var b = a // attention 只有 var 才可以轉換值下面會說明
如上一部份所示,變數A可以訪問(access) Cat 類別的物件
var a = Cat ()
var b = a
將a的值指派給b時,b取得指向同一物件的reference(參考)
b 和 a 都可以訪問(access)同一物件。也就是說b和a保存同一物件的reference(參考)。
所以實際上並不是在指派給b時,建立另一個Int物件讓b指向,而是讓 b 和 a 指向同一物件
b.equals(a) 會是 true
fun main() {
var a :Cat = Cat ()
var b = a
println(b.equals(a))
}
//true
上面有提到型態對編譯器很重要,兩個不同型態的變數,是不能互相傳遞值的
下面這樣會報錯,兩者型態不同,基本上無法編譯
var a :Int = 5
var c:Long = a
但在基礎型態中 , 但我們可以試著將他轉換成另一種型別
var a :Int = 5
var c:Long = a.toLong()
編譯器呼叫 Int 5 的 toLong()函式,會產生的新的值 Long 5,並將這個數值 傳給 c 變數,建立型態為Long 的 c 變數。
val 和 var 的差別在於 var 可以set Value 也可以 get value (可讀可寫),而 val 不行, val 只能get value(可讀) , 對一個變數的引用 是呼叫這個變數的getter方法, val 變數 在初始化時傳遞值給他,因為沒有set value, 所以並無法從新設定這個變數的值 ,這也就是當你初始化一個val 變數之後,再把其他值指派給他會報錯的原因。
1- 會報錯,無法編譯
val a = 5
a = 6
2- 可以從新設定 a 變數的值 , 不會報錯
var a = 5
a = 6
這個情形通常見於 一般的物件, 但基本型態是無法的哦
舉例如下:
val 變數 a 不能再指向其他 物件
val a = Cat()
a = Cat() // 會報錯,無法編譯
但我們可以改變本身 Cat() 的數值
fun main() {
val a = Cat()
// 更改 Cat() 類別的變數 name
a.name = "hello Kitty"
a.name = "Garfield"
println(a.name)
// result : Garfield
}
這時候保存的還是同一個物件 , 並沒有產生或引用新的物件哦。
還記得上面我們所說的,將a的值指派給b時,b可取得指向同一物件的reference(參考),b 和 a 都可以訪問(access) 同一物件。
val b = a
延續 上一個 Topic , 今天將 型別 為 Cat 的變數, 換成陣列 , val a 將其指向的物件(array 物件)指派給另一個變數 val b ,這時候 a 和 b 會指向同一物件。
val a = arrayOf(1,2,3)
val b = a
在指派值給b之後,變數b改變 position 0 的數字
b[0] = 8
結果連 a 變數都改變了 , 為啥?
fun main() {
val a = arrayOf(1,2,3)
var b = a
b[0] = 8
for (i in 0 until a.size){
println(a[i])
}
//result
//8
//2
//3
}
原來是因為 這兩個變數保存 同一物件的 reference (指向同一物件) , 當一個變數對這物件作非本質上的更改時會影響到其他變數
物件有可能發生本質上的改變 ,像 MutableList 產生的物件 在調用 sortedByDescending ()做降序排列時,就會產生新的物件 , 所以下面 b 和 a 會指向同一物件 , a 會把同一個物件的 reference 給 b , 而 c 則是 a 所指向的 物件執行 sortedByDescending ()所產生新的物件 , 所持有的 物件 reference 和 a 或 b 都不同
fun main() {
val a =mutableListOf<Int>(1,2,3)
var b = a
var c = a.sortedByDescending{it}
println(b === a)
// result : true
println(c === a)
// result : false
}
基礎型態,是 Immutable (無法像物件那樣做更改, 他只是個值) ,上面我們有提到 Kotlin 在基礎型態有 Byte、Short、Int、Long、Float、Double、Char與Boolean,
在這些型態被傳遞 , 傳遞是傳遞實際基本型態的 值 , 像是 5 (Int) , True (Bolean), 103.0 (Double),會把這些數值傳給 另一個變數
物件是 mutable (可以做非本質上的更改 , 像上面提到的那樣),物件和變數關係,是將物件 reference(參考) 傳遞給另一個變數,並非傳遞實際的數值,讓這值個變數可以access (訪問)這個物件,reference 可以看作是 找這物件的地址 。
String 是物件 , 但是 和 基礎型態 一樣 Immutable , JVM 有一個 String Pool , String Pool 負責將不同 字的片段 組成 一個物件 , 當編譯器看到文字時,它將在池中查找。如果找到匹配項,則變數會指向 舊有的String 物件,系統並且不會創建新的 String 物件 給變數引用。
這是使String 物件不可變原因在於: 在 String Pool 中,一個 String 物件可能具有一個或多個變數指向它。如果多個變數甚至不知道指向同一 String 物件,那麼如果其中一個引用修改了該 String 物件,那會照成混亂。這就是為什麼String 物件是 Immutable 。
下面 b 變數 和 a 變數 指向同一個 String 物件 ,
c 變數 會指向新的物件 , 這個物件是從 String Pool 找到匹配 的另一個 String 物件 , 並非是 "1" String 物件 做實值上更改
fun main() {
val a = "1"
var b = a
var c = a +"2"
println(b === a)
// result : true
println(c === a)
// result : false
}
好的 , 今天結束 , 做個練習吧 ,測試下列四個組數值是否指到同一物件及值的變化,是否和想像的一樣 答案明天會公佈
第一組
fun main (){
var a = 0
var b = a
b = 1
}
第二組
fun main (){
var sa = "abcd"
var sb = sa
sb.replace("a","c")
}
第三組
fun main (){
var la = mutableListOf(1,2,3,4)
var lb = la
lb.clear()
}
第四組
data class Test (var id:Int, var name :String)
fun main (){
var ta = Test(0,"aaa")
var tb = ta
tb.id = 1
}