Learn Kotlin

Kotlin優(yōu)勢(shì)

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

構(gòu)造函數(shù)

在 Kotlin 中的一個(gè)類可以有一個(gè)主構(gòu)造函數(shù)和一個(gè)或多個(gè)次級(jí)構(gòu)造函數(shù)湖苞。主構(gòu)造函數(shù)是類頭的一部分:它跟在類名后拯欧。

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

如果主構(gòu)造函數(shù)沒(méi)有任何注解或者可見(jiàn)性修飾符,可以省略這個(gè) constructor關(guān)鍵字财骨。

class Person(firstName: String) {
}

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

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

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

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

事實(shí)上该贾,聲明屬性以及從主構(gòu)造函數(shù)初始化屬性,Kotlin 有簡(jiǎn)潔的語(yǔ)法捌臊,與普通屬性一樣杨蛋,主構(gòu)造函數(shù)中聲明的屬性可以是可變的(var)或只讀的(val):

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

如果構(gòu)造函數(shù)有注解或可見(jiàn)性修飾符,這個(gè) constructor 關(guān)鍵字是必需的理澎,并且這些修飾符在它前面:

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

次級(jí)構(gòu)造函數(shù)

類也可以聲明前綴有 constructor的次構(gòu)造函數(shù)六荒。
如果類有一個(gè)主構(gòu)造函數(shù),每個(gè)次構(gòu)造函數(shù)需要委托給主構(gòu)造函數(shù)矾端, 可以直接委托或者通過(guò)別的次構(gòu)造函數(shù)間接委托掏击。委托到同一個(gè)類的另一個(gè)構(gòu)造函數(shù)用 this 關(guān)鍵字即可。
如果你沒(méi)有委托主構(gòu)造函數(shù)秩铆,系統(tǒng)會(huì)提示:Primary constructor call expected

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

如果一個(gè)非抽象類沒(méi)有聲明任何(主或次)構(gòu)造函數(shù)砚亭,它會(huì)有一個(gè)生成的不帶參數(shù)的主構(gòu)造函數(shù)。構(gòu)造函數(shù)的可見(jiàn)性是 public殴玛。如果你不希望你的類有一個(gè)公有構(gòu)造函數(shù)捅膘,你需要聲明一個(gè)帶有非默認(rèn)可見(jiàn)的空的主構(gòu)造函數(shù):

class DontCreateMe private constructor () {
}

繼承

在 Kotlin 中所有類都有一個(gè)共同的超類 Any,它是沒(méi)有繼承父類的類的默認(rèn)超類:

class Example // 從 Any 隱式繼承

默認(rèn)每個(gè)類在創(chuàng)建的時(shí)候都是final的滚粟,如果沒(méi)有添加open關(guān)鍵字寻仗,你在繼承的時(shí)候系統(tǒng)會(huì)提示This type is final, so it cannot be inherited from

要聲明一個(gè)顯式的父類凡壤,我們把類型放到類頭的冒號(hào)之后:

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

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

如果類沒(méi)有主構(gòu)造函數(shù),那么每個(gè)次構(gòu)造函數(shù)必須使用 super 關(guān)鍵字初始化其父類型硝烂,或委托給另一個(gè)構(gòu)造函數(shù)做到這一點(diǎn)箕别。 注意,在這種情況下,不同的次構(gòu)造函數(shù)可以調(diào)用父類型的不同的構(gòu)造函數(shù):

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

如果你不執(zhí)行這一步串稀,系統(tǒng)會(huì)提示你Explicit "this" or ''super" call is required. There is no constructor in superclass that can be called without arguments
類上的open 標(biāo)注與 Java 中 final 相反除抛,它允許其他類從這個(gè)類繼承。
默認(rèn)情況下母截,在 Kotlin 中所有的類都是 final到忽。
要么為繼承而設(shè)計(jì),并提供文檔說(shuō)明微酬,要么就禁止繼承绘趋。

伴生對(duì)象

在 Kotlin 中類沒(méi)有static的方法和變量颤陶,所以需要使用Companion Object來(lái)聲明類似static的方法和變量颗管。
其實(shí)這些變量并不是真正的static變量,而是一個(gè)伴生對(duì)象滓走,這個(gè)伴生對(duì)象位于類中定義的一個(gè)叫做Companion的內(nèi)部類中垦江。
類內(nèi)部的對(duì)象聲明可以用 companion 關(guān)鍵字標(biāo)記:

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

該伴生對(duì)象的成員可通過(guò)只使用類名作為限定符來(lái)調(diào)用:

val instance = MyClass.create()

在Java中如何調(diào)用Companion Object的屬性和方法呢?

MyClass.INSTANCE.create()

當(dāng)然搅方,在 JVM 平臺(tái)比吭,如果使用 @JvmStatic @JvmField注解,你可以將伴生對(duì)象的成員生成為真正的
靜態(tài)方法和字段姨涡。

我們來(lái)看一下Companion Object的具體應(yīng)用場(chǎng)景:


CapaCameraActivity.png

字節(jié)碼:


字節(jié)碼.png

Decompile To Java:


Decompile To Java.png

Getter And Setter

首先來(lái)看在Kotlin中如何聲明一個(gè)屬性衩藤,屬性可以用關(guān)鍵字var 聲明為可變的,否則使用只讀關(guān)鍵字val涛漂。

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

其實(shí)赏表,聲明一個(gè)屬性的完整語(yǔ)法是:

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

其中,initializer匈仗、setter瓢剿、getter都是可選的。屬性的類型如果可以從initializer或getter中推斷出來(lái)悠轩,也可以省略间狂。
其中,一個(gè)只讀屬性(val)和一個(gè)可變屬性(var)的區(qū)別是:只讀屬性不允許setter火架。

一個(gè)自定義gettter的例子:

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

一個(gè)自定義setter的例子:

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

如果你需要改變一個(gè)訪問(wèn)器的可見(jiàn)性或者對(duì)其注解鉴象,但是不需要改變默認(rèn)的實(shí)現(xiàn), 你可以定義訪問(wèn)器而不定義其實(shí)現(xiàn):

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

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

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

擴(kuò)展函數(shù)

擴(kuò)展函數(shù)數(shù)是指在一個(gè)類上增加一種新的行為何鸡,甚至我們沒(méi)有這個(gè)類代碼的訪問(wèn)權(quán)限炼列。
Koltin可以對(duì)一個(gè)類的屬性和方法進(jìn)行擴(kuò)展,它是一種靜態(tài)行為音比,對(duì)擴(kuò)展的類代碼不會(huì)造成任何影響俭尖。
擴(kuò)展函數(shù)的定義形式:

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

一個(gè)簡(jiǎn)單的擴(kuò)展函數(shù)的舉例:

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

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

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

項(xiàng)目中已有的最簡(jiǎn)便的擴(kuò)展函數(shù)的應(yīng)用(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擴(kuò)展函數(shù)允許我們?cè)诓桓淖円延蓄惖那闆r下稽犁,為類添加新的函數(shù)焰望。
最常用的擴(kuò)展函數(shù)的實(shí)例:

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

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

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

End

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市已亥,隨后出現(xiàn)的幾起案子熊赖,更是在濱河造成了極大的恐慌,老刑警劉巖虑椎,帶你破解...
    沈念sama閱讀 207,248評(píng)論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件震鹉,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡捆姜,警方通過(guò)查閱死者的電腦和手機(jī)传趾,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,681評(píng)論 2 381
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)泥技,“玉大人浆兰,你說(shuō)我怎么就攤上這事∩罕” “怎么了簸呈?”我有些...
    開(kāi)封第一講書(shū)人閱讀 153,443評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)店茶。 經(jīng)常有香客問(wèn)我蜕便,道長(zhǎng),這世上最難降的妖魔是什么贩幻? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 55,475評(píng)論 1 279
  • 正文 為了忘掉前任轿腺,我火速辦了婚禮,結(jié)果婚禮上段直,老公的妹妹穿的比我還像新娘吃溅。我一直安慰自己,他們只是感情好鸯檬,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,458評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布决侈。 她就那樣靜靜地躺著,像睡著了一般喧务。 火紅的嫁衣襯著肌膚如雪赖歌。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 49,185評(píng)論 1 284
  • 那天功茴,我揣著相機(jī)與錄音庐冯,去河邊找鬼。 笑死坎穿,一個(gè)胖子當(dāng)著我的面吹牛展父,可吹牛的內(nèi)容都是我干的返劲。 我是一名探鬼主播,決...
    沈念sama閱讀 38,451評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼栖茉,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼篮绿!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起吕漂,我...
    開(kāi)封第一講書(shū)人閱讀 37,112評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤亲配,失蹤者是張志新(化名)和其女友劉穎,沒(méi)想到半個(gè)月后惶凝,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體吼虎,經(jīng)...
    沈念sama閱讀 43,609評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,083評(píng)論 2 325
  • 正文 我和宋清朗相戀三年苍鲜,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了思灰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 38,163評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡坡贺,死狀恐怖官辈,靈堂內(nèi)的尸體忽然破棺而出箱舞,到底是詐尸還是另有隱情遍坟,我是刑警寧澤,帶...
    沈念sama閱讀 33,803評(píng)論 4 323
  • 正文 年R本政府宣布晴股,位于F島的核電站愿伴,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏电湘。R本人自食惡果不足惜隔节,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,357評(píng)論 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望寂呛。 院中可真熱鬧怎诫,春花似錦、人聲如沸贷痪。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 30,357評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)劫拢。三九已至肉津,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間舱沧,已是汗流浹背妹沙。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 31,590評(píng)論 1 261
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留熟吏,地道東北人距糖。 一個(gè)月前我還...
    沈念sama閱讀 45,636評(píng)論 2 355
  • 正文 我出身青樓玄窝,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親悍引。 傳聞我的和親對(duì)象是個(gè)殘疾皇子哆料,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,925評(píng)論 2 344

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

  • 前言 人生苦多,快來(lái) Kotlin 吗铐,快速學(xué)習(xí)Kotlin东亦! 什么是Kotlin? Kotlin 是種靜態(tài)類型編程...
    任半生囂狂閱讀 26,146評(píng)論 9 118
  • 面向?qū)ο缶幊蹋∣OP) 在前面的章節(jié)中,我們學(xué)習(xí)了Kotlin的語(yǔ)言基礎(chǔ)知識(shí)镊逝、類型系統(tǒng)壮啊、集合類以及泛型相關(guān)的知識(shí)。...
    Tenderness4閱讀 4,419評(píng)論 1 6
  • Kotlin的類和接口與Java的類和接口是有一定的區(qū)別的。Kotlin的接口是可以包含屬性聲明座菠。Kotlin默認(rèn)...
    程自舟閱讀 10,318評(píng)論 0 11
  • 寫在開(kāi)頭:本人打算開(kāi)始寫一個(gè)Kotlin系列的教程浴滴,一是使自己記憶和理解的更加深刻拓萌,二是可以分享給同樣想學(xué)習(xí)Kot...
    胡奚冰閱讀 1,412評(píng)論 5 11
  • 不重要的廢話 前段時(shí)間看了一遍《Programming Kotlin》,主要目的是想提高自己的英文閱讀能力升略,能力提...
    珞澤珈群閱讀 3,336評(píng)論 1 7