Kotlin是一門強類型的語言,Kotlin編譯器對類型檢查很是嚴格,這種嚴格保證了Kotlin程序的健壯,所以Kotlin不一樣類型的值常常須要進行相互轉換,數值型之間的變量和值也能夠相互轉換。html
不一樣整型的變量能支持的表數範圍是不一樣的,好比Byte類型的變量或常量只能接受-128~127之間的整數,Short類型的變量或常量只能接受-32768~32767之間的整數。若是數值超出了變量或常量所支持的表數範圍,編譯器就會報錯。例如以下代碼:java
// Byte類型支持的表數範圍爲-32768~32767,因此下面代碼報錯編程
var negative: Short = 40000安全
// Byte類型支持的表數範圍爲-128~127,因此下面代碼報錯app
var big: Byte = 128dom
簡單來講,Kotlin與Java不一樣,Kot不支持取值範圍小的數據類型隱式轉換爲取值範圍大的類型。ide
因爲不一樣整型支持的表數範圍存在差別,所以進行類型轉換時必須注意選擇合適的類型。Kotlin爲全部數值類型都提供了以下方法進行轉換。post
Kotlin要求不一樣整型的變量或值之間必須進行顯式轉換。例如以下代碼。ui
程序清單:codes\02\2.6\IntConvert.kt編碼
fun main(args: Array<String>) {
var bookPrice : Byte = 79
var itemPrice : Short = 120
// bookPrice是Byte類型,但變量a是Short類型,所以下面代碼錯誤
// var a: Short = bookPrice
// 顯式將bookPrice強制轉換爲Int16類型
var a: Short = bookPrice.toShort() // ①
var b: Byte = itemPrice.toByte()
println("a: ${a}, b: ${b}")
val amount = 233
// 將Int型變量轉換爲Byte類型,發生溢出
val byteAmount: Byte = amount.toByte() // ②
println(byteAmount)
}
上面程序中第一行粗體字代碼試圖將bookPrice(Byte類型的變量)賦值給變量a,但因爲變量a是Short類型,雖然它們都是整型,但Kotlin依然不容許直接賦值,所以這行代碼沒法經過編譯。
程序中①號粗體字代碼先將bookPrice強制轉換爲Short類型,這樣便可將轉換後的結果賦值給Short類型的變量a了;接下來的代碼則調用itemPrice的toByte()方法將Short類型的變量轉換爲Byte類型。
與Java相似的是,把取值範圍大的變量或表達式強轉爲取值範圍小的類型時,可能發生溢出。例如上面程序中②號代碼所示。上面程序還把233強制類型轉換爲Byte型整數,從而變成了23,這就是典型的溢出。圖2.3示範了這個轉換過程。
圖2.3 int類型向byte類型強制類型轉換
從圖3.11能夠看出,32位Int類型的233在內存中如圖2.3上面所示,強制類型轉換爲8位的Byte類型,則須要截斷前面的24位,只保留右邊8位,最左邊的1是符號位,此處代表這是一個負數,負數在計算機裏是以補碼形式存在的,所以還須要換算成原碼。
將補碼減1獲得反碼形式,再將反碼取反就能夠獲得原碼。
最後的二進制原碼爲10010111,這個byte類型的值爲-(16 + 4 + 2 + 1),也就是-23。
從圖2.3很容易看出,當試圖強制把表數範圍大的類型轉換爲表數範圍小的類型時,必須格外當心,由於很是容易引發信息丟失。
雖然Kotlin缺少隱式轉換,但Kotlin在表達式中又可能夠自動轉換,這種轉換是基於上下文推斷出來,並且算術運算會有重載作適當轉換,例如以下代碼(程序清單同上)。
// 算術表達式中bookPrice、itemPrice會自動提高爲Int類型
var total = bookPrice + itemPrice // ③
println("total的值爲:${total}")
// 可看到total映射的Java類型爲int
println("total的類型爲:${total.javaClass}")
// 下面表達式中bookPrice強制轉換爲Logn類型,所以整個表達式類型爲Long
val tot = bookPrice.toLong() + itemPrice.toByte() // ④
println("total的值爲:${tot}")
// 可看到total映射的Java類型爲long
println("total的類型爲:${tot.javaClass}")
上面③號代碼將bookPrice(Byte類型)和itemPrice(Short類型)相加,Kotlin並不須要對它們進行強制轉換,Kotlin將會自動把它們提高到Int類型以後再進行計算(與Java表達式對全部整型的處理規則相同),所以整個表達式計算獲得的結果是Int類型。
上面④號代碼先將bookPrice的類型強轉換爲Long類型,這樣整個表達式中最高等級的操做數是Long類型,所以整個表達式計算獲得的結果也是Long類型。
提示:上面程序中使用了變量的javaClass屬性,該屬性來自Any類型(Any類型是Kotlin全部類型的根父類),javaClass屬性用於獲取指定變量對應的Java類型(大體至關於Java反射中的getClass()方法)。
Kotlin雖然不容許直接將Char當成整數值使用,也不容許將整數值直接當成Char使用,但Kotlin依然可調用數值型的toChar()方法將數值型變量或表達式轉換爲Char類型。例以下面程序示範瞭如何生成一個6位的隨機字符串,這個程序中用到了後面的循環控制,不理解循環的讀者能夠參考後面章節的介紹。
程序清單:codes\02\2.6\RandomStr.kt
fun main(args: Array<String>) {
// 定義一個空字符串
var result = "";
// 進行6次循環
for(i in 0..5) {
// 生成一個97~122之間的Int類型整數
val intVal = (Math.random() * 26 + 97).toInt();
// 將intValue強制轉換爲Char類型後鏈接到result後面
result = result + intVal.toChar();
}
// 輸出隨機字符串
println(result);
}
此外,Char型雖然不能被當成整數進行算術運算,但Kotlin爲Char類型提供了加、減運算支持,其計算規則以下:
q Char型的值加、減一個整型值:Kotlin會先將該Char值對應的字符編碼進行加、減該整數,而後將計算結果轉換爲Char值。
q 兩個Char值進行相減:Kotlin將用兩個Char值對應的字符編碼進行減法運算,最後返回Int類型的值。兩個Char型的值不能相加。
例如以下程序。
程序清單:codes\02\2.6\CharAdd.kt
fun main(args: Array<String>) {
var c1 = 'i'
var c2 = 'k'
println(c1 + 4); // 輸出m
println(c1 - 4); // 輸出e
println((c1 - c2)); // 輸出-2
}
Kotlin的Float、Double之間須要進行顯式轉換,浮點型與整型之間也須要進行顯式轉換—這些轉換過程與前面介紹的整型之間的轉換過程基本類似。例如以下程序。
程序清單:codes\02\2.6\FloatConvert.kt
fun main(args: Array<String>) {
var width: Float =
var height: Double = 4.5
// width必須顯式強制轉換爲Double以後,才能賦值給變量a
var a: Double = width.toDouble()
println("a的值爲: ${a}")
// 將height強制轉換爲Float以後再進行計算,整個表達式的類型都是Float類型
// 所以area1的類型也被推斷爲Float類型
var area1 = width * height.toFloat()
// 表達式中height是Double類型,它是等級最高的運算數
// 所以整個表達式的類型都是Double類型,area2的類型也被推斷爲Double類型
var area2 = width * height
val multi: Int = 5
// 所以totalHeight1的類型也被推斷爲Double類型
var totalHeight1 = height * multi // ①
// 將height強制轉換爲Int後進行計算,整個表達式的類型都是Int類型
// 所以totalHeight2的類型也被推斷爲Int類型
var totalHeight2 = height.toInt() * multi // ②
}
上面程序中第一行粗體字代碼但願將Float類型的width變量賦值給Double類型的變量a,所以程序必須先進行類型轉換。接下來程序試圖將width和height相乘的積賦給area一、area2,若是咱們但願area1變量的類型是Float,這就須要將height強轉爲Float類型,這樣整個表達式中width、height都是Float類型,整個表達式的計算結果也是Float類型。area2則將被推斷爲Double類型。
上面程序中①號粗體字代碼計算multi、height的乘積,因爲height的類型是Double類型,所以整個表達式的類型是double類型,所以totalHeight1的類型也是Double類型。
程序中②號粗體字代碼先將height強制轉換爲Int類型,而後與multi(也是Int類型)變量相乘,這樣代碼也是正確的。
將Double類型或Float類型的值、變量或常量強制轉換爲整型時,浮點值的小數部分會被截斷,例如4.75將會變成四、-2.9將會被截斷爲-2。對於②號粗體字代碼而言,height被強制轉換爲Int類型,此時小數部分將會截斷,所以height將會被截斷爲4,所以計算獲得的totalHeight2的值爲20。
經過上面的介紹不難發現,當進行類型轉換時,應該儘可能向表數範圍大的數據類型轉換,這樣程序會更加安全,好比前面介紹的Byte向Short轉換、Int向Double轉換,而反過來轉換則可能致使溢出。Kotlin語言各類數值型的表數範圍由小到大的順序爲:Byte→Short→Int→Long→Float→Double。
當一個算術表達式中包含多個數值型的值時,整個算術表達式的數據類型將發生自動提高。Kotlin定義了與Java基本類似的自動提高規則。
下面程序示範了一個典型的錯誤。
程序清單:codes\02\2.6\AutoPromote.kt
// 定義一個Short類型變量
var sValue: Short = 5
// 表達式中的sValue將自動提高到Int類型,則右邊的表達式類型爲Int
// 將一個Int類型值賦給Short類型變量將發生錯誤
sValue = sValue - 2
上面的「sValue–2」表達式的類型將被提高到Int類型,這樣就把右邊的Int類型值賦給左邊的Short類型變量,從而引發錯誤。
下面代碼是表達式類型自動提高的正確示例代碼(程序清單同上)。
var b: Byte = 40
var c: Short = 97
var i: Int = 23
var d: Double = .314
// 右邊表達式中最高等級操做數爲d(Double類型)
// 則右邊表達式的類型爲Double類型,result將會推斷爲Double類型
val result = b + c + i * d
// 將輸出144.222
println(result)
必須指出,表達式的類型將嚴格保持和表達式中最高等級操做數相同的類型。下面代碼中兩個Int類型整數進行除法運算,即便沒法除盡,也將獲得一個int類型結果(程序清單同上)。
var iVal: Int = 3
// 右邊表達式中兩個操做數都是Int類型,故右邊表達式的類型爲Int
// 雖然23/3不能除盡,但依然獲得一個Int類型整數
val intResult = 23 / iVal;
println(intResult) // 將輸出7
從上面程序中能夠看出,當兩個整數進行除法運算時,若是不能整除,獲得的結果將是把小數部分截斷取整後的整數。
若是表達式中包含了字符串,則又是另外一番情形了。由於當把加號(+)放在字符串和數值之間時,這個加號是一個字符串鏈接運算符,而不是進行加法運算。看以下代碼:
// 輸出字符串Hello!a7
println("Hello!" + 'a' + 7)
// 輸出字符串hHello!
println('a' + 7 + "Hello!"))
對於第一個表達式「"Hello!" + 'a' +
以上內容節選自《瘋狂Kotlin講義》:一本讓您最直接認識Kotlin的瘋狂講義