HelloKotlin

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ǔ)法

資料來源

Kotlin教程
案例地址

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市杨幼,隨后出現(xiàn)的幾起案子撇簿,更是在濱河造成了極大的恐慌,老刑警劉巖推汽,帶你破解...
    沈念sama閱讀 211,817評(píng)論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件补疑,死亡現(xiàn)場(chǎng)離奇詭異歧沪,居然都是意外死亡歹撒,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,329評(píng)論 3 385
  • 文/潘曉璐 我一進(jìn)店門诊胞,熙熙樓的掌柜王于貴愁眉苦臉地迎上來暖夭,“玉大人,你說我怎么就攤上這事撵孤÷踝牛” “怎么了?”我有些...
    開封第一講書人閱讀 157,354評(píng)論 0 348
  • 文/不壞的土叔 我叫張陵邪码,是天一觀的道長(zhǎng)裕菠。 經(jīng)常有香客問我,道長(zhǎng)闭专,這世上最難降的妖魔是什么奴潘? 我笑而不...
    開封第一講書人閱讀 56,498評(píng)論 1 284
  • 正文 為了忘掉前任旧烧,我火速辦了婚禮,結(jié)果婚禮上画髓,老公的妹妹穿的比我還像新娘掘剪。我一直安慰自己,他們只是感情好奈虾,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,600評(píng)論 6 386
  • 文/花漫 我一把揭開白布夺谁。 她就那樣靜靜地躺著,像睡著了一般肉微。 火紅的嫁衣襯著肌膚如雪匾鸥。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 49,829評(píng)論 1 290
  • 那天碉纳,我揣著相機(jī)與錄音扫腺,去河邊找鬼。 笑死村象,一個(gè)胖子當(dāng)著我的面吹牛笆环,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播厚者,決...
    沈念sama閱讀 38,979評(píng)論 3 408
  • 文/蒼蘭香墨 我猛地睜開眼躁劣,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來了库菲?” 一聲冷哼從身側(cè)響起账忘,我...
    開封第一講書人閱讀 37,722評(píng)論 0 266
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎熙宇,沒想到半個(gè)月后鳖擒,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 44,189評(píng)論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡烫止,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,519評(píng)論 2 327
  • 正文 我和宋清朗相戀三年蒋荚,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片馆蠕。...
    茶點(diǎn)故事閱讀 38,654評(píng)論 1 340
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡期升,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出互躬,到底是詐尸還是另有隱情播赁,我是刑警寧澤,帶...
    沈念sama閱讀 34,329評(píng)論 4 330
  • 正文 年R本政府宣布吼渡,位于F島的核電站容为,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜坎背,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,940評(píng)論 3 313
  • 文/蒙蒙 一竭缝、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧沼瘫,春花似錦抬纸、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,762評(píng)論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至膜蛔,卻和暖如春坛猪,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背皂股。 一陣腳步聲響...
    開封第一講書人閱讀 31,993評(píng)論 1 266
  • 我被黑心中介騙來泰國(guó)打工墅茉, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人呜呐。 一個(gè)月前我還...
    沈念sama閱讀 46,382評(píng)論 2 360
  • 正文 我出身青樓就斤,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親蘑辑。 傳聞我的和親對(duì)象是個(gè)殘疾皇子洋机,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,543評(píng)論 2 349

推薦閱讀更多精彩內(nèi)容

  • 前言 人生苦多,快來 Kotlin 洋魂,快速學(xué)習(xí)Kotlin绷旗! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,168評(píng)論 9 118
  • Google在今年的IO大會(huì)上宣布副砍,將Android開發(fā)的官方語(yǔ)言更換為Kotlin衔肢,作為跟著Google玩兒An...
    藍(lán)灰_q閱讀 76,794評(píng)論 31 489
  • 入職公司第三周時(shí),項(xiàng)目組讓我用kotlin去完成一個(gè)內(nèi)部使用的app豁翎。下面記錄一下kotlin相關(guān)筆記角骤。因?yàn)閍pp...
    楊hai閱讀 1,121評(píng)論 1 8
  • 初中畢業(yè)的時(shí)候刘陶,我才認(rèn)識(shí)他。認(rèn)真算起來牢撼,9年了匙隔。 我從來沒有見過他。 我稱他蕭熏版。很久之前就想過寫寫吧纷责,寫寫蕭的故事...
    荔枝_妹妹閱讀 122評(píng)論 2 1
  • 近日再膳,在群里聽了一位業(yè)內(nèi)的超級(jí)銷售大咖分享的一個(gè)精彩案例挺勿,可謂精彩、非常有學(xué)習(xí)借鑒價(jià)值喂柒,但是之后就在思考一個(gè)問題不瓶,...
    熊貓大叔閱讀 674評(píng)論 0 0