Learn Kotlin

Kotlin優(yōu)勢

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

構造函數(shù)

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

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

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

class Person(firstName: String) {
}

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

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

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

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

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

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

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

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

次級構造函數(shù)

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

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

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

class DontCreateMe private constructor () {
}

繼承

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

class Example // 從 Any 隱式繼承

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

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

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

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

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

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

如果你不執(zhí)行這一步,系統(tǒng)會提示你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注解,你可以將伴生對象的成員生成為真正的
靜態(tài)方法和字段。

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


CapaCameraActivity.png

字節(jié)碼:


字節(jié)碼.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)的區(qū)別是:只讀屬性不允許setter。

一個自定義gettter的例子:

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

一個自定義setter的例子:

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

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

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

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

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

擴展函數(shù)

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

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

一個簡單的擴展函數(shù)的舉例:

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

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

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

項目中已有的最簡便的擴展函數(shù)的應用(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擴展函數(shù)允許我們在不改變已有類的情況下,為類添加新的函數(shù)。
最常用的擴展函數(shù)的實例:

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

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發(fā)布,文章內容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容