Kotlin VS Java
createTime : 2017.08.29
updateTime : 2017.09.14
author : 老機(jī)長(zhǎng)
version : 1.5.0
審閱者:pighead猖毫、社會(huì)我道哥
0.What is Kotlin ?
- Kotlin 是一個(gè)基于 JVM 的新的編程語(yǔ)言,由 JetBrains 開發(fā)。
- Kotlin可以編譯成Java字節(jié)碼产还,也可以編譯成JavaScript喇澡,方便在沒有JVM的設(shè)備上運(yùn)行椭员。
- JetBrains雨涛,作為目前廣受歡迎的Java IDE IntelliJ 的提供商衍菱,在 Apache 許可下已經(jīng)開源其Kotlin 編程語(yǔ)言赶么。
- Kotlin已正式成為Android官方支持開發(fā)語(yǔ)言。
1.基礎(chǔ)語(yǔ)法
(1.1) 包 及 類的導(dǎo)入脊串、注釋
a. 定義包 :
package xx.xxx.xxxx
b. 導(dǎo)入包 :
import xx.xxx.xxxx
c. 代碼注釋:
c1 .行注釋:
// 這是一條行末注釋
c2. 段落注釋 :
/* 這是一條塊注釋
可以包含多行內(nèi)容. */
(1.2) 定義變量
a. 只讀變量:
val i:Int = 10
val i = 1 // 變量類型自動(dòng)推斷為 `Int` 類型
//當(dāng)一個(gè)引用可能為 null 值時(shí), 對(duì)應(yīng)的類型聲明必須明確地標(biāo)記為可為 null
fun mutily(x: Int?, y: Int?): Int? {
if (x == null) {
println("Wrong number format in x")
return null
}
if (y == null) {
println("Wrong number format in y")
return null
}
return x * y
}
b. 可寫變量:
var i = 1
(1.3) 定義函數(shù)
//標(biāo)準(zhǔn)定義,該函數(shù)接受兩個(gè) Int 類型參數(shù), 并返回 Int 類型結(jié)果
fun sum(a: Int, b: Int): Int {
return a + b
}
//該函數(shù)使用表達(dá)式語(yǔ)句作為函數(shù)體, 返回類型由自動(dòng)推斷決定
fun sum(a: Int, b: Int) = a + b
//若該函數(shù)不需要返回值如何處理 辫呻?清钥??
fun printSum(a: Int, b: Int): Unit {
print(a + b)
}
//notice 返回值為 Unit 類型時(shí), 可以省略
fun printSum(a: Int, b: Int) {
print(a + b)
}
(1.4) 字符串模板
fun main(args: Array<String>) {
if (args.size == 0) return
print("First argument: ${args[0]}")
}
案例參見: BaseDemo.kt
(1.5) 邏輯控制 if and when and for
案例參見:ControlDemo.kt
(1.6) 返回及跳轉(zhuǎn)
案例參見:BreakDemo.kt
2. 類與繼承
(2.1) 類的定義
a. Kotlin 中的類使用 class 關(guān)鍵字定義
package com.laojizhang.kotlin.clazz
//類的定義由以下幾部分組成: 類名, 類頭部(指定類的類型參數(shù), 主構(gòu)造器, 等等.), 以及由大括號(hào)括起的類主體部分. 類的頭部和主體部分都是可選的; 如果類沒有主體部分, 那么大括號(hào)也可以省略.
//如果一個(gè)非抽象類沒有聲明任何主構(gòu)造器和次級(jí)構(gòu)造器, 它將帶有一個(gè)自動(dòng)生成的, 無參數(shù)的主構(gòu)造器. 這個(gè)構(gòu)造器的可見度為 public
class EmptyClass
open class Person(val name: String = "")
class Person1 constructor(name: String)
//上面兩種主構(gòu)造函數(shù)有區(qū)別嗎 放闺?祟昭??
// 問:我們?cè)趯慗ava的時(shí)候怖侦,有時(shí)候可能會(huì)寫好幾個(gè)構(gòu)造方法篡悟,這種情況怎么處理呢?匾寝?
// 答:次級(jí)構(gòu)造函數(shù)
open class Person2(val name: String) {
// 如果類有主構(gòu)造器, 那么每個(gè)次級(jí)構(gòu)造器都必須委托給主構(gòu)造器, 要么直接委托, 要么通過其他次級(jí)構(gòu)造器間接委托. 委托到同一個(gè)類的另一個(gè)構(gòu)造器時(shí), 使用 this 關(guān)鍵字實(shí)現(xiàn):
constructor(name: String, age: Int) : this(name)
open val city: String = "beijing"
open fun eat() {
println("在 Person2 類中 eat")
}
fun sleep() {}
}
// 問: 有一個(gè)類我們不允許其他人直接實(shí)例化 又該怎么處理搬葬??艳悔?
// 答: 如果不希望你的類帶有 public 的構(gòu)造器, 你需要聲明一個(gè)空的構(gòu)造器, 并明確設(shè)置其可見度:
class Person3 private constructor()
class ClassDemo {
// 初始化代碼段
init {
println("這是初始化代碼段急凰,可以執(zhí)行一些你需要的初始化操作")
}
}
fun main(args: Array<String>) {
//類的實(shí)例化
val person = Person("laojizhang")
println("name = " + person.name)
// val person1 = Person1("laojizhang")
// println(person1.name)
val female = Male("laojizhang", 18, true)
female.eat()
println("Companion = " + MyClass.Companion)
println(MyClass.create())
val user = User("老機(jī)長(zhǎng)", 18, 1, "北京 朝陽(yáng) 三里屯")
val (a, b, c, d) = user
val (name, address) = user
println("name = $a address = $d")
println("name = $name address = $address")
}
// 子類繼承
// note:類上的 open 注解(annotation) 與 Java 的 final 正好相反: 這個(gè)注解表示允許從這個(gè)類繼承出其他子類. 默認(rèn)情況下, Kotlin 中所有的類都是 final 的
class Male(val name1: String, val age: Int, val sex: Boolean) : Person2(name1, age) {
// 屬性復(fù)寫
override val city: String
get() = "帝都"
// 方法重寫
override fun eat() {
// super.eat()
println("在 Male 類中 eat")
}
fun drink() {
println("在 Male 類中 drink")
}
}
//在 Kotlin 中, 類繼承中的方法實(shí)現(xiàn)問題, 遵守以下規(guī)則: 如果一個(gè)類從它的直接超類中繼承了同一個(gè)成員的多個(gè)實(shí)現(xiàn), 那么這個(gè)子類必須覆蓋這個(gè)成員, 并提供一個(gè)自己的實(shí)現(xiàn)(可以使用繼承得到的多個(gè)實(shí)現(xiàn)中的某一個(gè)). 為了表示使用的方法是從哪個(gè)超類繼承得到的, 我們使用 super 關(guān)鍵字, 將超類名稱放在尖括號(hào)類, 比如, super<Base>:
//同時(shí)繼承 A 和 B 是合法的, 而且函數(shù) a() 和 b() 的繼承也不存在問題, 因?yàn)閷?duì)于這兩個(gè)函數(shù), C 類都只繼承得到了唯一的一個(gè)實(shí)現(xiàn). 但對(duì)函數(shù) f() 的繼承就發(fā)生了問題, 因?yàn)?C 類從超類中繼承得到了兩個(gè)實(shí)現(xiàn), 因此在 C 類中我們必須覆蓋函數(shù) f(), 并提供我們自己的實(shí)現(xiàn), 這樣才能消除歧義.
open class A {
open fun f() {
print("A")
}
fun a() {
print("a")
}
}
interface B {
fun f() {
print("B")
} // 接口的成員默認(rèn)是 'open' 的
fun b() {
print("b")
}
}
class C() : A(), B {
// 編譯器要求 f() 方法必須覆蓋:
override fun f() {
super<A>.f() // 調(diào)用 A.f()
// super<B>.f() // 調(diào)用 B.f()
}
}
// Companion Object(同伴對(duì)象 伴生對(duì)象)
// 與 Java 或 C# 不同, Kotlin 的類沒有靜態(tài)方法(static method). 大多數(shù)情況下, 建議使用包級(jí)函數(shù)(package-level function)替代靜態(tài)方法.
class MyClass private constructor() {
companion object {
fun create(): MyClass {
return MyClass()
}
}
}
// 抽象類
abstract class absClass {
abstract fun method1()
abstract fun method2()
}
interface MyInterface {
val property: Int
fun bar()
fun foo() {
// 方法體是可選的
}
}
class ChildClass(override val property: Int) : MyInterface {
override fun bar() {
TODO("not implemented") //To change body of created functions use File | Settings | File Templates.
}
override fun foo() {
super.foo()
}
}
// 封閉類 和枚舉的作用應(yīng)該是一樣的,沒用過 不作介紹猜年,有興趣自己了解吧
sealed class Expr {
class Const(val number: Double) : Expr()
class Sum(val e1: Expr, val e2: Expr) : Expr()
object NotANumber : Expr()
}
private class MyPrivateClass {
private val name: String = "privateClass"
}
// 數(shù)據(jù)類 and 解構(gòu)聲明
data class User(val name: String, val age: Int, val sex: Int, val address: String)
(2.2) 訪問修飾符
類, 對(duì)象, 接口, 構(gòu)造器, 函數(shù), 屬性, 以及屬性的設(shè)值方法, 都可以使用可見度修飾符.(屬性的取值方法永遠(yuǎn)與屬性本身的可見度一致, 因此不需要控制其可見度.)
Kotlin 中存在 4 種可見度修飾符: private, protected, internal(內(nèi)部的) 以及 public. 如果沒有明確指定修飾符, 則使用默認(rèn)的可見度 public.
說在前面 --- 模塊的概念
internal 修飾符表示這個(gè)成員只能在同一個(gè)模塊內(nèi)訪問. 更確切地說, 一個(gè)模塊(module)是指一起編譯的一組 Kotlin 源代碼文件:
一個(gè) IntelliJ IDEA 模塊;
一個(gè) Maven 工程, 或 Gradle 工程;
通過 Ant 任務(wù)的一次調(diào)用編譯的一組文件.
a. 包的訪問修飾符
如果你不指定任何可見度修飾符, 默認(rèn)會(huì)使用 public, 其含義是, 你聲明的東西在任何位置都可以訪問;
如果你將聲明的東西標(biāo)記為 private, 那么它將只在同一個(gè)源代碼文件內(nèi)可以訪問;
如果標(biāo)記為 internal, 那么它將在同一個(gè)模塊(module)內(nèi)的任何位置都可以訪問;
對(duì)于頂級(jí)(top-level)聲明, protected 修飾符是無效的.
b. 類和接口的訪問修飾符
private 表示只在這個(gè)類(以及它的所有成員)之內(nèi)可以訪問;
protected — 與 private 一樣, 另外在子類中也可以訪問;
internal — 在 本模塊之內(nèi), 凡是能夠訪問到這個(gè)類的地方, 同時(shí)也能訪問到這個(gè)類的 internal 成員;
public — 凡是能夠訪問到這個(gè)類的地方, 同時(shí)也能訪問這個(gè)類的 public 成員.
(2.3) 拓展
與 C# 和 Gosu 類似, Kotlin 提供了向一個(gè)類擴(kuò)展新功能的能力, 而且不必從這個(gè)類繼承, 也不必使用任何設(shè)計(jì)模式, 比如 Decorator 模式之類. 這種功能是通過一種特殊的聲明來實(shí)現(xiàn)的, Kotlin 中稱為 擴(kuò)展(extension).
Kotlin 支持 擴(kuò)展函數(shù)(extension function) 和 擴(kuò)展屬性(extension property).
a. 拓展函數(shù)
要聲明一個(gè)擴(kuò)展函數(shù), 我們需要在函數(shù)名之前添加前綴, 表示這個(gè)函數(shù)的 接收者類型(receiver type), 也就是說, 表明我們希望擴(kuò)展的對(duì)象類型. 以下示例將為 MutableList<Int> 類型添加一個(gè) swap 函數(shù):
b. 為所有對(duì)象增加一個(gè)printString方法
即使在對(duì)象變量值為 null 時(shí)也可以調(diào)用, 在擴(kuò)展函數(shù)的實(shí)現(xiàn)體之內(nèi), 可以通過 this == null 來檢查接收者是否為 null.
在 Kotlin 中允許你調(diào)用 toString() 函數(shù), 而不必檢查對(duì)象是否為 null, 就是通過這個(gè)原理實(shí)現(xiàn)的: 對(duì)象是否為 null 的檢查發(fā)生在擴(kuò)展函數(shù)內(nèi)部, 因此調(diào)用者不必再做檢查.
c. 拓展屬性
val <T> List<T>.lastIndex: Int
get() = size - 1
d. 對(duì)伴生類添加拓展函數(shù)
e. 在B類定義A類的拓展函數(shù)
案例參見:ExtensionDemo.kt
3. 異常
Kotlin異常和Java異陈招猓基本一致
Kotlin 中所有的異常類都是 Throwable 的后代類. 每個(gè)異常都帶有一個(gè)錯(cuò)誤消息, 調(diào)用堆棧, 以及可選的錯(cuò)誤原因.
a. try表達(dá)式
// try 表達(dá)式的返回值, 要么是 try 代碼段內(nèi)最后一個(gè)表達(dá)式的值, 要么是 catch 代碼段內(nèi)最后一個(gè)表達(dá)式的值. finally 代碼段的內(nèi)容不會(huì)影響 try 表達(dá)式的結(jié)果值.
val a: Int? = try { parseInt(input) } catch (e: NumberFormatException) { null }
b. Checked Exception(受控異常)
Kotlin 中不存在受控異常(checked exception)
下面的例子是 JDK 中 StringBuilder 類所實(shí)現(xiàn)的一個(gè)接口:
Appendable append(CharSequence csq) throws IOException
這個(gè)方法簽名代表什么意思? 它說, 每次我想要將一個(gè)字符串追加到某個(gè)對(duì)象(比如, 一個(gè) StringBuilder, 某種 log, 控制臺(tái), 等等), 我都必須要捕獲 IOException 異常.
為什么? 因?yàn)檫@個(gè)對(duì)象有可能會(huì)執(zhí)行 IO 操作 (比如 Writer 類也會(huì)實(shí)現(xiàn) Appendable 接口).因此就導(dǎo)致我們的程序中充滿了這樣的代碼:
try {
log.append(message)
}
catch (IOException e) {
// 實(shí)際上前面的代碼必然是安全的
}
高階函數(shù)
Kotlin 支持把函數(shù)賦值給變量并傳遞變量作為其他函數(shù)的參數(shù)。接受其他函數(shù)作為參數(shù)的函數(shù)稱為 高階函數(shù)
函數(shù)調(diào)用
一個(gè) Kotlin 函數(shù)可以由它的名字加前綴 :: 而引用乔外,或直接在代碼塊中聲明一個(gè)匿名函數(shù)床三,或使用 lambda 表達(dá)式語(yǔ)法