[Kotlin In Action學(xué)習(xí)筆記]

[Kotlin In Action學(xué)習(xí)筆記] [未完待續(xù)]

前言

使用kotlin進行android開發(fā)

kotlin非常適合開發(fā)android應(yīng)用程序,他將現(xiàn)代語言的所有優(yōu)勢帶入android平臺并且不會引入新的限制:

  • 兼容性。kotlin與jdk6 完全兼容,并且主流IDE都支持kotlin語言。
  • 性能。kotlin采用和java類似的字節(jié)碼結(jié)構(gòu),并且支持lambda等表達(dá)式使得kotlin與java的代碼運行類似或者更快。
  • 互操作性。kot;in與java可以100%的互操作。允許使用現(xiàn)有的android庫。
  • 學(xué)習(xí)曲線。kotlin對于java開發(fā)者入門十分簡單,IDE中的轉(zhuǎn)換器有助于開發(fā)者邁出第一步。
  • 占用。kotlin具有緊湊的運行時庫,并且可以通過Proguard進一步減少。
  • 編譯。kotlin支持高效的增量編譯。

用于android開發(fā)的工具

  • kotlin android擴展是一個編譯器擴展,可以讓你擺脫編譯器中的findviewbyid()
  • anko是一個圍繞android api的kotlin友好的包裝器的庫,以及可以使用kotlin代碼替換布局文件.xml的dsl

android開發(fā)入門

現(xiàn)在android studio/eclipse/intellij idea都已經(jīng)支持kotlin,其中android studio在3.0版本以后已經(jīng)默認(rèn)支持kotlin,用戶不用再下載kotlin插件,eclipse如何使用請自行g(shù)oogle,android studio3.0以前版本在settings-->plugins-->install jetbrains plugins搜索kotlin下載。下載之后重啟android studio,創(chuàng)建新項目完畢后,點擊菜單code-->convert java code to kotlin即可將項目自動生成的java代碼轉(zhuǎn)換成kotlin代碼。在菜單tools-->kotlin-->configure kotlin in project,選擇module和kotlin版本,一般直接確定即可。

kotlin android擴展

kotlin官方團隊的kotlin android擴展改進了對android支持,可以提高開發(fā)體驗。

開發(fā)者僅需要在module級別的build.gradle中添加

    apply plugin: 'kotlin-android-extensions'

配置了之后,在xml文件中定義了id,在activity/fragment中,輸入這個id,android studio的代碼聯(lián)想會自動聯(lián)想到對應(yīng)的資源文件,并自動添加依賴

import kotlinx.android.synthetic.main.<布局>.*

這樣就省去了大量的findviewbyid代碼。

kotlin 對android 框架的支持

ButterKnife

ButterKnife可以直接將view和變量進行綁定從而免去調(diào)用findViewById。

另外,Kotlin Android 擴展插件(Android Studio 內(nèi)置)具有同樣的效果:使用簡潔明了的代碼替換findViewByid。 除非現(xiàn)在你正在使用 ButterKnife 而且沒有遷移計劃,那么前者非常值得嘗試。

在 Kotlin 中使用 ButterKnife 與 Java 中完全一致。 在 Gradle 構(gòu)建腳本的修改如下,后面將重點介紹代碼部分的差異。

在 Gradle 依賴中添加 kotlin-kapt 插件,并使用 kapt 替代 annotationProcessor。

apply plugin: 'kotlin-kapt'

dependencies {
    ...
    compile "com.jakewharton:butterknife:$butterknife-version"
    kapt "com.jakewharton:butterknife-compiler:$butterknife-version"
}

我們已經(jīng)將整個 ButterKnife 示例代碼轉(zhuǎn)換為 Kotlin, 參見詳細(xì)代碼。

讓我門看看發(fā)生了什么變化。 在 Java 中使用注解對將變量與之對應(yīng)的 view 進行綁定:

@BindView(R2.id.title) TextView title;

在 Kotlin 中使用屬性而不是直接使用變量。 對屬性使用注解:

@BindView(R2.id.title)
lateinit var title: TextView

@BindView 被定義為僅應(yīng)用于變量字段,而將注解應(yīng)用于整個屬性時,Kotlin 編譯器能夠理解并且覆蓋相應(yīng)注解的字段。

lateinit 修飾符允許聲明非空類型,并在對象創(chuàng)建后(構(gòu)造函數(shù)調(diào)用后)初始化。 不使用 lateinit 則需要聲明可空類型并且有額外的空安全檢測操作。

使用 ButterKnife 注解可以將方法設(shè)置為監(jiān)聽器:

@OnClick(R2.id.hello)
internal fun sayHello() {
    Toast.makeText(this, "Hello, views!", LENGTH_SHORT).show()
}

以上代碼表示點擊“hello”按鈕后的事件響應(yīng)。 然而在 Kotlin 中使用 lambda 表達(dá)式會讓代碼更加簡潔清晰:

hello.setOnClickListener {
    toast("Hello, views!")
}

Anko 庫默認(rèn)提供 toast 函數(shù)。

詳情請參閱kotlin@kotliner.cn

語法基礎(chǔ)

1. 基礎(chǔ)語法

定義包

包的聲明處于源文件的頂部

package com.dou.kotlin.learnkotlin

kotlin源文件和包的結(jié)構(gòu)和目錄無需匹配,也就是說源文件可以放在任何文件目錄下。

定義函數(shù)

函數(shù)使用關(guān)鍵子fun,參數(shù)格式為 參數(shù):類型

// java轉(zhuǎn)kotlin自動生成的oncreate
override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    setContentView(R.layout.activity_main)
}

 // 參數(shù):(Int, Int),無返回值函數(shù)
fun printSum (a : Int, b : Int) : Unit {
    println("sum is " + (a + b))
}

// 參數(shù):(Int, Int),無返回值函數(shù),unit類型可以省略
fun printSum (a : Int, b : Int) {
    println("sum is " + (a + b))
}

// 參數(shù):(Int, Int), 返回:(Int)
fun sum (a : Int, b : Int) : Int {
    return a + b
}

// 參數(shù)(Int, Int), 返回(Int)
// 表達(dá)式作為函數(shù)體,返回類型自動推斷:
fun mutilply (a : Int, b : Int) = a * b

// 參數(shù)(Int, Int), 返回(Int)
fun mutilply (a : Int, b : Int) : Int = a * b
注釋
行注釋
// 這是行注釋 
多行注釋
/*這是多行注釋
*/

2. 基本數(shù)據(jù)類型

定義變量
定義一次賦值的變量

定義一次賦值的變量使用val修飾

val a : Int = 1 //立即賦值,定義變量類型為Int
val b = 2 //立即賦值,變量類型自動判斷為Int
val c : Int //如果沒有初始賦值必須定義變量類型
c = 3 // 明確賦值
定義可變變量
var a : Int = 3
var b = 3
var c : Int //如果沒有初始賦值必須定義變量類型
c = 3
使用字符串模板

字符串模板就是一小段代碼表示一個字符串。字符串模板以$表示

 var a = 1
 var b = "a is $a"
 
 a = 2
 var d = "${b.replace("is", "was")}, but now is $a"

3. 條件控制

if條件表達(dá)式
// 條件表達(dá)式
fun method4 (a : Int, b : Int) : Int{
    if (a > b) {
        return a
    } else {
        return b
    }
}

// 條件表達(dá)式,將函數(shù)式作為函數(shù)體
fun method5 (a: Int,b: Int) = if (a > b) a else b
when條件表達(dá)式

when相當(dāng)于java中的switch語句。
它的簡單形式是

when (參數(shù)) {
    條件 -> 語句 // 參數(shù)符合條件的情況
    else -> 語句 // 其它情況
}
或者
when {
    條件表達(dá)式 -> 語句 // 符合條件表達(dá)式的時候執(zhí)行
    else -> 語句 //其它情況
}

when將它的參數(shù)和所有分支條件順序比較,知道某個分支滿足條件。如果其它分支都不滿足條件,就會執(zhí)行else分支,如果when作為表達(dá)式使用,則必須指定else語句。

fun method16 () {
    var a = 9;
    when {
        a in 1..10 -> println("$a is in 1-10")
        a == 1 -> println("$a == 1")

        else -> println("other")
    }

    when (a) {
        !in 1..10 -> println("$a is not in 1-10")
        1 ->  println("$a == 1")

        else -> println("other")
    }

    fun hasPrefix (a: Any) = when (a) {
        is String -> a.contains("prefix")

        else -> false
    }
}

4. 循環(huán)控制

for循環(huán)

for循環(huán)可以對任何提供迭代器的對象進行遍歷,基本語法為

for (a: Int in arrays) {
    // ...
}

對集合進行遍歷

var items = listOf<String>("kotlin","java", "c", "c++");
for (i in items) {
    println(i)
}

for (i in items.indices) {
    print(items[i])
}
while循環(huán)

while循環(huán)基本的語法為

while(布爾表達(dá)式) {
    // 語句
}

do {
    // 執(zhí)行語句
} while (布爾表達(dá)式)
跳轉(zhuǎn)和返回

kotlin中跳轉(zhuǎn)和返回與java類似,有break,return,continue。
kotlin中所有表達(dá)式都可以用標(biāo)簽標(biāo)示。標(biāo)簽格式為 標(biāo)識符后加@符號,例如abc@,mark@,要為一個表達(dá)式添加標(biāo)簽,需要在這個表達(dá)式前加上標(biāo)簽即可。

loop@ for (i in 1..10) {
}

標(biāo)簽可以配合continue和break使用。當(dāng)有多層嵌套時,可以指定跳出到哪個循環(huán)體.

outer@ for (i in 1..20) {
    inner@ for (j in 1..20) {
        if (...) break@outer
    }
}

5. 其它

使用可空值和空值檢測

當(dāng)某個變量可以為空時,必須在變量類型聲明后使用?表示該變量可以為空

fun method6 (a : String?) {
    if (a == null) {
        println("a為空")
    } else{
        println(a)
    }
}

kotlin的空安全設(shè)計對于聲明可能為空的參數(shù),在使用時要做判空處理,一般有兩種處理方式:

  1. 變量后加!!表示為空時拋出異常
  2. 變量后加?表示不作處理返回null或者配合?:做空判斷處理
// 后邊加?表示變量可能為空
var a : String? = null

//  變量后加!!表示拋出異常
var b = a!!.toInt()

// 變量后加?表示返回null時不做處理
var c = a?.toInt()

// ?配合?!做空判斷處理
var d = a.toInt() ?: -1
類型檢測

is運算符用來檢測某個對象是否是某種類型的實例,相當(dāng)于java中的instance of,在檢測后,如果是某種類型的話,就可以直接當(dāng)做該類型使用,不用顯式的去轉(zhuǎn)換

if (obj is String) {
        return obj.length
} else {
    return null
}
使用區(qū)間
使用集合

2. 習(xí)慣用法

3. 編碼習(xí)慣

Kotlin基礎(chǔ)

筆記丟失了一部分之后再補上

數(shù)組

fun method18(){
    var items = arrayOf(1,2,3,4) // 創(chuàng)建一個確定的數(shù)組[1,2,3,4]
    for (i in items) {
        print(i)
    }

    var array1 = arrayOfNulls<Int>(4) // 創(chuàng)建一個空數(shù)組
    for (i in array1.indices) {
        array1[i] = i // 給數(shù)組元素賦值
    } 
}

// Array是一個工廠函數(shù), 第一個參數(shù)指定數(shù)組的大小,第二個參數(shù)表達(dá)式是根據(jù)數(shù)組索引指定每個元素的值
// 創(chuàng)建數(shù)組["1", "4", "9", "16"]
var array2 = Array(4, {i -> (i * i).toString()})

字符串

字符串用strng類型表示,字符串是不可變的。字符串的元素可以通過s[i]訪問。也可以用for循環(huán)迭代字符串。

字符串分為原生字符串和轉(zhuǎn)義字符串。

轉(zhuǎn)義字符串類似java中的字符串,用""包含起來,可以使用轉(zhuǎn)義字符。

原生字符串使用""" """包含起來,可以包括換行和任意文本。
默認(rèn)|作為邊界前綴。

fun method19 () {
    var str = """
        |這是原生字符串
        |這是原生字符串
        |這是原生字符串
    """ 
    //  輸出              |這是原生字符串    
    //  輸出              |這是原生字符串    
    //  輸出              |這是原生字符串

    var strTrim = """
        |這是原生字符串
        |這是原生字符串
        |這是原生字符串
    """.trimMargin() // 輸出 這是原生字符串
                             這是原生字符串
                              這是原生字符串

    var strCode = """
        for (i in 1..4) {
            print(i)
        }"""


    println(str)
    println(strTrim)
    println(strCode)
}

類和對象

kotlin中也是用關(guān)鍵字class聲明類。
類聲明由類名,類頭(指定類繼承,類構(gòu)造方法等)和大括號包起來的類體組成,如果一個雷沒有類體可以省略大括號。

類中可以有一個主構(gòu)造方法和多個次構(gòu)造方法,主構(gòu)造方法是類頭的一部分,跟在類名之后的,用constructor關(guān)鍵字修飾。如果主構(gòu)造函數(shù)沒有任何注解或者修飾可以省略。

class Person constructor(name: String)

class persion(name: String)

主構(gòu)造函數(shù)不能包含任何代碼。類的初始化操作可以放在類中init關(guān)鍵字的代碼塊中。

class Persion(name: String, id: Long) {

    var pName: String = name
    var pId: Long = id

    init {
        // ...
    }
}

主構(gòu)造方法可以直接聲明屬性。

class Persion(var name: String, var id: Long) {
    init {
        // ...
    }
}

次構(gòu)造方法的格式為

constructor(參數(shù): 參數(shù)類型) : this(...參數(shù))

this(...參數(shù))指代的是其它構(gòu)造方法。如果這個類中沒有主構(gòu)造方法是可以省略的。如果類中有構(gòu)造方法則這個類必須直接或者間接的委托主構(gòu)造方法。委托到另一個構(gòu)造方法用this關(guān)鍵字即可。

如果一個非抽象類沒有聲明任何構(gòu)造方法,那么這個類會默認(rèn)一個public的無參的主構(gòu)造方法。

要創(chuàng)建類的實例不需要且沒有java中的new關(guān)鍵字

類成員包括

  • 函數(shù)
  • 屬性
  • 嵌套類和內(nèi)部類
  • 對象聲明

屬性

屬性聲明

在類中可以用var修飾可變成員屬性和val修飾只讀成員屬性。

要使用一個屬性只用在對象后.該屬性名即可。

 var extendence = Extendence(1)
 print(extendence.name)
Getters和Setters

聲明一個屬性的完整語法是:

var <propertyName>[:    <PropertyType>] [=  <property_initializer>]
            [<getter>]
            [<setter>]

初始化器,getter,setter方法都是可選的

var allByDefault:   Int?    //  錯誤:需要顯式初始化器,隱含默認(rèn)    getter  和   setter
var initialized =   1   //  類型  Int、默認(rèn)  getter  和   setter

繼承

要去聲明一個顯式的超類,在類頭的最后加上:(超類名)(超類的構(gòu)造方法)

open class Base(p: Int)

class Extendence(p: Int) : Base(p)

如果子類有主構(gòu)造方法那么這個子類聲明中必須要用子類的構(gòu)造方法參數(shù)對父類進行初始化。如果子類沒有主構(gòu)造方法,那么在每個次構(gòu)造方法必須使用super關(guān)鍵字初始化父類類型或者委托給其它的構(gòu)造函數(shù)做到這一點。

class Extendence : Base{
    constructor(p: Int) : super(p)
    constructor(p:Int, a: Int) : this(p)
}
Any

Any是所有類的超類,但是Any類中只有三個方法,equals(),toString(),hashCode()。

fianl,open關(guān)鍵字

open代表該類可以被繼承,類默認(rèn)是final修飾的,也就是不能被繼承。

覆蓋方法

kotlin需要顯式的標(biāo)注可被覆蓋的成員和被覆蓋的成員。

open class Base(p: Int) {
    open fun method(){}
}

class Extendence : Base{
    constructor(p: Int) : super(p)
    constructor(p:Int, a: Int) : this(p)

    override fun method(){}
}

也就是說方法覆蓋中父類和子類方法都要加修飾。父類的方法前要加open,子類方法要加override。如果父類方法沒有用open修飾,子類不允許出現(xiàn)與父類相同簽名的方法(同名同參同返回值)。

標(biāo)記為override的成員本身也是開放的,可以被再次覆蓋,如果想要禁止再次覆蓋,需要使用final關(guān)鍵字。

open class Entendence(p: Int) : Base(p){
    final override fun method(){}
}
覆蓋屬性

覆蓋屬性的基本用法和覆蓋方法類似。父類屬性用open修飾,子類屬性用override修飾。

你可以用一個var屬性覆蓋一個val屬性,但是不能用val屬性覆蓋一個var.因為var屬性本質(zhì)上聲明了一個getter和setting方法,val屬性本質(zhì)上只能聲明getter方法。

覆蓋規(guī)則

kotlin支持多繼承,如果一個子類繼承多個父類且父類中存在同樣的屬性或者方法,那么這個子類必須覆蓋這個方法。

open class A(p: Int){
    open fun f(){}
    fun v()}{
}

interface B{
    fun f(){}
    fun v(){}
}

class C(p: Int) : A(P),B{
    override fun f() {
        super<A>.f();
        super<B>.f();
    }
    
    fun v(){}
}
抽象類

類或者類中的成員可以被聲明為abstract,被聲明為抽象的對象默認(rèn)是開放的。

需要注意的是我們可以用抽象的成員去覆蓋飛抽象成員。

伴生對象

伴生對象的作用類似與java中的靜態(tài)成員

封裝

多態(tài)

接口

可見性修飾符

數(shù)據(jù)類

密封類

泛型

嵌套

枚舉

對象

委托

委托屬性

函數(shù)和lambda表達(dá)式

高級

其它

后記

參考

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容