Learn Kotlin

Kotlin優勢

  • 空安全 :在編譯時期處理各種null情況,避免執行時異常。
  • 函數式支持:它使用了很多函數式編程概念。
  • 擴展函數:可以給任何類添加擴展函數。
  • 高度互操作性:Kotlin和Java兩個語言之間可以互操作,兩種語言互相調用,混合編程。

構造函數

在 Kotlin 中的一個類可以有一個主構造函數和一個或多個次級構造函數。主構造函數是類頭的一部分:它跟在類名后。

//firstName可以在initializer blocks中使用
class Person constructor(firstName: String) {
}

如果主構造函數沒有任何注解或者可見性修飾符,可以省略這個 constructor關鍵字。

class Person(firstName: String) {
}

主構造函數不能包含任何的代碼。
初始化的代碼可以放到以 init 關鍵字作為前綴的初始化塊(initializer blocks)中:

class Person(name: String) {
    init {
        CLog.d("Person initialized with name ${name}")
    }
}

注意,主構造的參數可以在初始化塊中使用。它們也可以在類體內中聲明屬性時使用:

class Person(name: String) {
    val customerKey = name.toUpperCase()
}

事實上,聲明屬性以及從主構造函數初始化屬性,Kotlin 有簡潔的語法,與普通屬性一樣,主構造函數中聲明的屬性可以是可變的(var)或只讀的(val):

class Person(val firstName: String, val lastName: String, var age: Int) {
    // ……
}

如果構造函數有注解或可見性修飾符,這個 constructor 關鍵字是必需的,并且這些修飾符在它前面:

class Person private constructor(name: String) {
    //......
}

次級構造函數

類也可以聲明前綴有 constructor的次構造函數。
如果類有一個主構造函數,每個次構造函數需要委托給主構造函數, 可以直接委托或者通過別的次構造函數間接委托。委托到同一個類的另一個構造函數用 this 關鍵字即可。
如果你沒有委托主構造函數,系統會提示:Primary constructor call expected

class Person(val name: String) {
    constructor(name: String, parent: Person) : this(name) {
        parent.children.add(this)
    }
}

如果一個非抽象類沒有聲明任何(主或次)構造函數,它會有一個生成的不帶參數的主構造函數。構造函數的可見性是 public。如果你不希望你的類有一個公有構造函數,你需要聲明一個帶有非默認可見的空的主構造函數:

class DontCreateMe private constructor () {
}

繼承

在 Kotlin 中所有類都有一個共同的超類 Any,它是沒有繼承父類的類的默認超類:

class Example // 從 Any 隱式繼承

默認每個類在創建的時候都是final的,如果沒有添加open關鍵字,你在繼承的時候系統會提示This type is final, so it cannot be inherited from

要聲明一個顯式的父類,我們把類型放到類頭的冒號之后:

open class Base(p: Int)
class Derived(p: Int) : Base(p)

如果該父類有一個主構造函數,則子類可以(并且必須) 用父類型的)主構造函數參數就地初始化。如果沒有執行這一步,系統會提示This type has a constructor , and thus must be initailized here

如果類沒有主構造函數,那么每個次構造函數必須使用 super 關鍵字初始化其父類型,或委托給另一個構造函數做到這一點。 注意,在這種情況下,不同的次構造函數可以調用父類型的不同的構造函數:

class MyView : View {
    constructor(context: Context) : super(context)
    constructor(context: Context, attrs: AttributeSet) : super(context, attrs)
}

如果你不執行這一步,系統會提示你Explicit "this" or ''super" call is required. There is no constructor in superclass that can be called without arguments
類上的open 標注與 Java 中 final 相反,它允許其他類從這個類繼承。
默認情況下,在 Kotlin 中所有的類都是 final。
要么為繼承而設計,并提供文檔說明,要么就禁止繼承。

伴生對象

在 Kotlin 中類沒有static的方法和變量,所以需要使用Companion Object來聲明類似static的方法和變量。
其實這些變量并不是真正的static變量,而是一個伴生對象,這個伴生對象位于類中定義的一個叫做Companion的內部類中。
類內部的對象聲明可以用 companion 關鍵字標記:

class MyClass {
    companion object Factory {
        fun create(): MyClass = MyClass()
    }
}

該伴生對象的成員可通過只使用類名作為限定符來調用:

val instance = MyClass.create()

在Java中如何調用Companion Object的屬性和方法呢?

MyClass.INSTANCE.create()

當然,在 JVM 平臺,如果使用 @JvmStatic @JvmField注解,你可以將伴生對象的成員生成為真正的
靜態方法和字段。

我們來看一下Companion Object的具體應用場景:


CapaCameraActivity.png

字節碼:


字節碼.png

Decompile To Java:


Decompile To Java.png

Getter And Setter

首先來看在Kotlin中如何聲明一個屬性,屬性可以用關鍵字var 聲明為可變的,否則使用只讀關鍵字val

class Address {
    var name: String = ……
    var street: String = ……
    var city: String = ……
    var state: String? = ……
    var zipCode: String = ……
}

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

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

其中,initializer、setter、getter都是可選的。屬性的類型如果可以從initializer或getter中推斷出來,也可以省略。
其中,一個只讀屬性(val)和一個可變屬性(var)的區別是:只讀屬性不允許setter。

一個自定義gettter的例子:

val isEmpty: Boolean
    get() = this.size == 0

一個自定義setter的例子:

var stringRepresentation: String
    get() = this.toString()
    set(value) {
        setDataFromString(value) // 解析字符串并賦值給其他屬性
    }

如果你需要改變一個訪問器的可見性或者對其注解,但是不需要改變默認的實現, 你可以定義訪問器而不定義其實現:

var setterVisibility: String = "abc"
    private set // 此 setter 是私有的并且有默認實現

var setterWithAnnotation: Any? = null
    @Inject set // 用 Inject 注解此 setter

具體使用場景:需要自定義getter和setter的方法舉例:

擴展函數

擴展函數數是指在一個類上增加一種新的行為,甚至我們沒有這個類代碼的訪問權限。
Koltin可以對一個類的屬性和方法進行擴展,它是一種靜態行為,對擴展的類代碼不會造成任何影響。
擴展函數的定義形式:

fun receiverType.functionName(params){
    body
}
  • receiverType:表示函數的接收者,也就是函數擴展的對象
  • . :擴展函數的修飾符
  • functionName:擴展函數的名稱
  • params:擴展函數的參數,可以為NULL

一個簡單的擴展函數的舉例:

//聲明一個User類
class User(var name:String)

//定義一個簡單的打印User名字的擴展函數
fun User.Print(){
    print("用戶名 $name")
}

fun main(arg:Array<String>){
    var user = User("Runoob")
    user.Print()
}

項目中已有的最簡便的擴展函數的應用(ViewExtensions):

package com.xingin.common

import android.text.SpannableString
import android.view.View
import android.widget.TextView

/**
 * Created by chris on 03/08/2017.
 */
fun View.hide() {
    this.visibility = View.GONE
}
fun View.show() {
    this.visibility = View.VISIBLE
}
fun View.showIf(shouldShow: Boolean) {
    this.visibility = if (shouldShow) View.VISIBLE else View.GONE
}
fun View.hideIf(shouldHide: Boolean) {
    showIf(!shouldHide)
}

fun TextView.setTextOrHide(text: CharSequence) {
    this.text = text
    showIf(text.isNotEmpty())
}

import java.io.File

/**
 * Created by Kathy on 2017/9/25.
 */
fun File.mkdirIfNotExists() {
    if (!exists()) mkdirs()
}

fun File.deleteIfIsFile() {
    if (isFile && exists()) delete()
}
public final class FileExtensionsKt {
   public static final void mkdirIfNotExists(@NotNull File $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      if(!$receiver.exists()) {
         $receiver.mkdirs();
      }

   }

   public static final void deleteIfIsFile(@NotNull File $receiver) {
      Intrinsics.checkParameterIsNotNull($receiver, "$receiver");
      if($receiver.isFile() && $receiver.exists()) {
         $receiver.delete();
      }

   }

Kotlin擴展函數允許我們在不改變已有類的情況下,為類添加新的函數。
最常用的擴展函數的實例:

fun Context.toast(message: CharSequence, duration: Int = Toast.LENGTH_SHORT) {
    Toast.makeText(this, message, duration).show()
}

然后在我們的Activity中將它作為普通方法來直接使用:

override fun onCreate(savedInstanceState: Bundle?) { 
    toast("This is onCreate!!")
    toast("Hello world!", Toast.LENGTH_LONG)
    toast(message = "Hello world!", duration = Toast.LENGTH_LONG)
}

End

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,001評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,786評論 3 423
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,986評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,204評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,964評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,354評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,410評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,554評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,106評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,918評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,093評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,648評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,342評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,755評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,009評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,839評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,107評論 2 375

推薦閱讀更多精彩內容