按照國際慣例,學習一門新的語言一般都是從「Hello World」開始的,在這裏也不例外,先看下 Java 中的 main
方法如何用 Kotlin 來表示java
fun main(args: Array<String>) {
println("Hello World")
}
複製代碼
從這裏能夠看出 Kotlin 相比 Java 有幾點不一樣git
此外,Kotlin 的最新版本已經能夠省略 main
方法的參數了github
在 Java 中,大部分的變量是可變的,意味着任何能夠訪問到這個變量的代碼均可以去修改它。而在 Kotlin 中,變量能夠分爲 可變變量(var) 和 不可變變量(val) 兩類編程
聲明變量的關鍵字有兩個:數組
不可變變量在賦值以後就不能再去改變它的狀態了,所以不可變變量能夠說是線程安全的,由於它們沒法改變,全部線程訪問到的對象都是同一個,所以也不須要去作訪問控制,開發者應當儘量地使用不可變變量,這樣可讓代碼更加接近函數式編程風格安全
此外,在 Kotlin 中一切都是對象,沒有像 Java 中那樣的原始基本類型,但 byte、char、integer、float 或者 boolean 等類型仍然有保留,可是所有都做爲對象存在ide
看如下例子函數式編程
fun main(args: Array<String>) {
//只讀變量即賦值後不能夠改變值的變量,用 val 聲明
//聲明一個整數類型的不可變變量
val intValue: Int = 100
//聲明一個雙精度類型的可變變量
var doubleValue: Double = 100.0
}
複製代碼
在聲明變量時咱們一般不須要指明變量的類型,這能夠由編譯器根據上下文自動推導出來函數
fun main(args: Array<String>) {
//在聲明變量時咱們一般不須要指明變量的類型,這能夠由編譯器根據上下文自動推導出來
val intValue = 100
var doubleValue = 100.0
//若是隻讀變量在聲明時沒有初始值,則必須指明變量類型
val intValue2: Int
intValue2 = 10
}
複製代碼
與 Java 不一樣,Kotlin 並不區分基本數據類型和它的包裝類,在 Kotlin 中一切都是對象,能夠在任何變量上調用其成員函數和屬性學習
對於基本類型,Kotlin 相比 Java 有幾點特殊的地方
//在 Kotlin 中,int、long、float 等類型仍然存在,可是是做爲對象存在的
val intIndex: Int = 100
//等價於,編譯器會自動進行類型推導
val intIndex = 100
//數字類型不會自動轉型,必需要進行明確的類型轉換
val doubleIndex: Double = intIndex.toDouble()
//如下代碼會提示錯誤,須要進行明確的類型轉換
//val doubleIndex: Double = intIndex
val intValue: Int = 1
val longValue: Long = 1
//如下代碼會提示錯誤,由於二者的數據類型不一致,須要轉換爲同一類型後才能進行比較
//println(intValue == longValue)
//Char 不能直接做爲數字來處理,須要主動轉換
val ch: Char = 'c'
val charValue: Int = ch.toInt()
//如下代碼會提示錯誤
//val charValue: Int = ch
//二進制
val value1 = 0b00101
//十六進制
val value2 = 0x123
複製代碼
此外,Kotlin 的可空類型不能用 Java 的基本數據類型表示,由於 null 只能被存儲在 Java 的引用類型的變量中,這意味着只要使用了基本數據類型的可空版本,它就會被編譯成對應的包裝類型
//基本數據類型
val intValue_1: Int = 200
//包裝類
val intValue_2: Int? = intValue_1
val intValue_3: Int? = intValue_1
//== 比較的是數值相等性,所以結果是 true
println(intValue_2 == intValue_3)
//=== 比較的是引用是否相等,所以結果是 false
println(intValue_2 === intValue_3)
複製代碼
若是 intValue_1 的值是100,就會發現 intValue_2 === intValue_3 的比較結果是 true,這就涉及到 Java 對包裝類對象的重複使用問題了
Any 類型是 Kotlin 全部非空類型的超類型,包括像 Int 這樣的基本數據類型
若是把基本數據類型的值賦給 Any 類型的變量,則會自動裝箱
val any: Any = 100
println(any.javaClass) //class java.lang.Integer
複製代碼
若是想要使變量能夠存儲包括 null 在內的全部可能的值,則須要使用 Any?
val any: Any? = null
複製代碼
Kotlin 中的 Unit 類型相似於 Java 中的 void,能夠用於函數沒有返回值時的狀況
fun check(): Unit {
}
//若是返回值爲 Unit,則能夠省略該聲明
fun check() {
}
複製代碼
Unit 是一個完備的類型,能夠做爲類型參數,但 void 不行
interface Test<T> {
fun test(): T
}
class NoResultClass : Test<Unit> {
//返回 Unit,但能夠省略類型說明,函數也不須要顯式地 return
override fun test() {
}
}
複製代碼
Nothing 類型沒有任何值,只有被當作函數返回值使用,或者被當作泛型函數返回值的類型參數使用時纔會有意義,能夠用 Nothing 來表示一個函數不會被正常終止,從而幫助編譯器對代碼進行診斷
編譯器知道返回值爲 Nothing 類型的函數從不正常終止,因此編譯器會把 name1 的類型推斷爲非空,由於 name1 在爲 null 時的分支處理會始終拋出異常
data class User(val name: String?)
fun fail(message: String): Nothing {
throw IllegalStateException(message)
}
fun main(args: Array<String>) {
val user = User("leavesC")
val name = user.name ?: fail("no name")
println(name) //leavesC
val user1 = User(null)
val name1 = user1.name ?: fail("no name")
println(name1.length) //IllegalStateException
}
複製代碼
Kotlin 中的函數以關鍵字 fun 做爲開頭,函數名稱緊隨其後,再以後是用括號包裹起來的參數列表,若是函數有返回值,則再加上返回值類型,用一個冒號與參數列表隔開
//fun 用於表示聲明一個函數,getNameLastChar 是函數名
//空括號表示該函數無傳入參數,Char 表示函數的返回值類型是字符
fun getNameLastChar(): Char {
return name.get(name.length - 1)
}
複製代碼
//帶有兩個不一樣類型的參數,一個是 String 類型,一個是 Int 類型
//返回值爲 Int 類型
fun test1(str: String, int: Int): Int {
return str.length + int
}
複製代碼
此外,表達式函數體的返回值類型能夠省略,返回值類型能夠自動推斷。對於有返回值的代碼塊函數,必須顯式地寫出返回類型和 return 語句
//getNameLastChar 函數的返回值類型以及 return 關鍵字是能夠省略的
//返回值類型能夠由編譯器根據上下文進行推導
//所以,函數能夠簡寫爲如下形式
fun getNameLastChar() = name.get(name.length - 1)
複製代碼
若是無返回值,則能夠聲明 Unit ,也能夠省略 Unit
如下三種寫法都是等價的
fun test(str: String, int: Int): Unit {
println(str.length + int)
}
fun test(str: String, int: Int) {
println(str.length + int)
}
fun test(str: String, int: Int) = println(str.length + int)
複製代碼