Kotlin 語法基礎(chǔ)大全其骄,從例子著手的 從0到1的學(xué)習(xí) -- 基礎(chǔ)介紹

Kotlin 語法基礎(chǔ)大全亏镰,從例子著手的 從0到1的學(xué)習(xí) -- 基礎(chǔ)介紹
Kotlin 語法基礎(chǔ)大全,從例子著手的 從0到1的學(xué)習(xí) -- 流程控制
Kotlin 語法基礎(chǔ)大全拯爽,從例子著手的 從0到1的學(xué)習(xí) -- 特殊的類
Kotlin 語法基礎(chǔ)大全索抓,從例子著手的 從0到1的學(xué)習(xí) -- 函數(shù)
Kotlin 語法基礎(chǔ)大全,從例子著手的 從0到1的學(xué)習(xí) -- 集合
Kotlin 語法基礎(chǔ)大全毯炮,從例子著手的 從0到1的學(xué)習(xí) -- 作用域
Kotlin 語法基礎(chǔ)大全逼肯,從例子著手的 從0到1的學(xué)習(xí) -- 代理
Kotlin 語法基礎(chǔ)大全,從例子著手的 從0到1的學(xué)習(xí) -- 產(chǎn)品級特性
翻譯來源

hello world

package org.kotlinlang.play         // 1

fun main() {                        // 2
    println("Hello, World!")        // 3
}
  • 1 kotlin 一般定義在包里桃煎。但是如果你不定義那么就將內(nèi)容放到默認的包中篮幢。
  • 2 main方法是程序的入口。 在 Kotlin 1.3 main方法可以不定義任何參數(shù)也不需要定義返回值为迈。
  • 3 println 方法將會把一行內(nèi)容輸入到標(biāo)準輸出三椿。這個方法已經(jīng)默認引用了,不需要顯式的引用葫辐。分號也不再是必須的搜锰。

在早于1.3版本main 方法必須要有參數(shù)

fun main(args: Array<String>) {
    println("Hello, World!")
}

方法

普通方法
fun printMessage(message: String): Unit {                               // 1
    println(message)
}

fun printMessageWithPrefix(message: String, prefix: String = "Info") {  // 2
    println("[$prefix] $message")
}

fun sum(x: Int, y: Int): Int {                                          // 3
    return x + y
}

fun multiply(x: Int, y: Int) = x * y                                    // 4

fun main() {
    printMessage("Hello")                                               // 5                    
    printMessageWithPrefix("Hello", "Log")                              // 6
    printMessageWithPrefix("Hello")                                     // 7
    printMessageWithPrefix(prefix = "Log", message = "Hello")           // 8
    println(sum(1, 2))                                                  // 9
}
  • 1 一個簡單的方法,帶有一個string參數(shù)和返回unit 就是返回void 沒有返回值
  • 2 一個帶有兩個參數(shù)的方法耿战,其中 info是一個帶有默認值的方法纽乱,無返回值就是默認Unit

通過tools show kotlin bytecode 再decompile 可以看到kotlin的java代碼長什么樣子


fun printMessageWithPrefix(message: String, prefix: String = "Info") {  // 2
    println("[$prefix] $message")
}

fun main() {
    printMessageWithPrefix("1")
    printMessageWithPrefix("1", "2")
}

kotlin代碼轉(zhuǎn)化之后成為的樣子,·從這可以看到kotlin在這里的處理是創(chuàng)建一個不同名字的方法昆箕,直接改了調(diào)用的地方,不是如預(yù)想中的重載·


  public static final void printMessageWithPrefix(@NotNull String message, @NotNull String prefix) {
     Intrinsics.checkParameterIsNotNull(message, "message");
     Intrinsics.checkParameterIsNotNull(prefix, "prefix");
     String var2 = '[' + prefix + "] " + message;
     boolean var3 = false;
     System.out.println(var2);
  }

  // $FF: synthetic method
  public static void printMessageWithPrefix$default(String var0, String var1, int var2, Object var3) {
     if ((var2 & 2) != 0) {
        var1 = "Info";
     }

     printMessageWithPrefix(var0, var1);
  }

  public static final void main() {
     printMessageWithPrefix$default("1", (String)null, 2, (Object)null);
     printMessageWithPrefix("1", "2");
  }

  // $FF: synthetic method
  public static void main(String[] var0) {
     main();
  }
  • 3 一個返回int的值的方法
  • 4 只有一個表達式的方法租冠,并且推斷返回值為int
  • 5 調(diào)用了第一個方法傳入了一個hello 的參數(shù)
  • 6 調(diào)用了第二個方法傳入了兩個參數(shù)
  • 7 調(diào)用了第二個方法傳入了一個參數(shù)鹏倘,第二個參數(shù)info帶有默認值info
  • 8 調(diào)用了第二個方法傳入了帶命名的參數(shù),這使得參數(shù)不再是按照參數(shù)順序來傳入的
  • 9 打印方法的返回值
infix functions 中綴方法

如果成員方法和擴展方法只有一個參數(shù)那么可以轉(zhuǎn)化為中綴方法

fun main() {

  infix fun Int.times(str: String) = str.repeat(this)        // 1
  println(2 times "Bye ")                                    // 2

  val pair = "Ferrari" to "Katrina"                          // 3
  println(pair)

  infix fun String.onto(other: String) = Pair(this, other)   // 4
  val myPair = "McLaren" onto "Lucas"
  println(myPair)

  val sophia = Person("Sophia")
  val claudia = Person("Claudia")
  sophia likes claudia                                       // 5
}

class Person(val name: String) {
  val likedPeople = mutableListOf<Person>()
  infix fun likes(other: Person) { likedPeople.add(other) }  // 6
}
  • 1 定義一個中綴擴展方法在 Int 類里
  • 2 嗲用這個方法
  • 3 創(chuàng)建一個pair 通過標(biāo)準庫里的中綴方法 to
  • 4 創(chuàng)建一個你自己的 類似于to的方法 onto
  • 5 中綴符號 也可以定義成 成員方法顽爹,用于類對象使用
  • 6 定義了中綴方法的類將會成為這個方法里面的第一個參數(shù)纤泵,即有個默認的this

local functions 內(nèi)部方法
定義在方法中的方法

操作符方法

明確的方法可以升級為 操作符方法,允許調(diào)用者使用相應(yīng)的符號進行運算

operator fun Int.times(str: String) = str.repeat(this)       // 1
println(2 * "Bye ")                                          // 2

operator fun String.get(range: IntRange) = substring(range)  // 3
val str = "Always forgive your enemies; nothing annoys them so much."
println(str[0..14])                                          //14
  • 1 操作符和對應(yīng)的重載方法是一一對應(yīng)的 times 方法就是對應(yīng) *的,相當(dāng)于重載操作符了
  • 2 times 對應(yīng)了 * 你調(diào)用 2 * "Bye " 相當(dāng)與 調(diào)用了 2.times("Bye ")
  • 3 get(range: IntRange) ==> [0 .. 14]
  • 4 可以參考這篇文章
帶有 vararg 參數(shù)的方法

vararg 就相當(dāng)于 java 中 String... args

fun printAll(vararg messages: String) {                            // 1
    for (m in messages) println(m)
}
printAll("Hello", "Hallo", "Salut", "Hola", "你好")                 // 2

fun printAllWithPrefix(vararg messages: String, prefix: String) {  // 3
    for (m in messages) println(prefix + m)
}
printAllWithPrefix(
    "Hello", "Hallo", "Salut", "Hola", "你好",
    prefix = "Greeting: "                                          // 4
)

fun log(vararg entries: String) {
    printAll(*entries)                                             // 5
}
  • 1 如何獲取 vararg中的每個參數(shù)
  • 2 你也可以傳入任意數(shù)量的參數(shù)包括0個
  • 3 由于有命名參數(shù)的存在你可以在可變長度的參數(shù)后面再添加一個同類型的參數(shù)镜粤,二這一點在java中是做不到的
  • 4 你應(yīng)該像這樣一樣使用
  • 5 在運行時中捏题,vararg 是以數(shù)組的形式傳遞到參數(shù)中,這和java是一樣的肉渴。你可以用* 將可變長度的參數(shù)以可變長度的參數(shù)來傳遞而不是以數(shù)組的方式來傳遞公荧。這里不加 * 將會報錯。

變量

kotlin 具有強大的變量的推斷能力同规。你可以明確的定義變量的類型循狰,也可以讓編譯器自己來推斷變量類型是什么窟社。推薦使用val 來定義變量,因為這是不變的變量绪钥,當(dāng)然kotlin 也不會強制你將變量定義為不變灿里,你可以使用var。

var a: String = "initial"  // 1
println(a)
val b: Int = 1             // 2
val c = 3                  // 3
  • 1 定義了一個可變變量程腹,并且初始化
  • 2 定義了一個不可變變量匣吊,并且初始化。相當(dāng)于java中添加了 final
  • 3 定義了一個不可變變量寸潦,并且初始化色鸳,并且沒有明確定義變量名稱。類型將由編譯器推斷甸祭,這里編譯器推斷的是Int
var e: Int  // 1
println(e)  // 2
  • 1 定義了一個變量并且沒有對他進行初始化
  • 2 這里將會報錯缕碎,變量必須進行初始化

你可以在任何地方進行初始化,只要在read 這個變量之前就可以池户。這里和java 不同

val d: Int  // 1

if (someCondition()) {
    d = 1   // 2
} else {
    d = 2   // 2
}

println(d) // 3
  • 1 定義一個不可變的變量
  • 2 根據(jù)一些條件進行判斷 之后再初始化
  • 3 read 這個變量咏雌,這里不報錯,因為已經(jīng)初始化了

空安全檢查

kotlin 想要創(chuàng)造一個沒有NullPointerException的世界校焦,所以不允許給一個變量賦予Null值赊抖。如果你確實需要賦予一個變量null,請在他的類型名稱之后加上?

var neverNull: String = "This can't be null"            // 1

neverNull = null                                        // 2

var nullable: String? = "You can keep a null here"      // 3

nullable = null                                         // 4

var inferredNonNull = "The compiler assumes non-null"   // 5

inferredNonNull = null                                  // 6

fun strLength(notNull: String): Int {                   // 7
    return notNull.length
}

strLength(neverNull)                                    // 8
strLength(nullable)                                     // 9
  • 1 定義了一個不可為空的String寨典,并且賦值
  • 2 將這個字符串設(shè)置為null(這里將會報錯)
  • 3 定義一個可為空的String氛雪,并且賦值
  • 4 將這個字符串設(shè)置為null,這里沒有報錯
  • 5 定義一個由編譯器進行推斷的變量耸成,這里編譯器推斷為String报亩。編譯器將會把變量優(yōu)先推斷為非空類型
  • 6 報錯,因為編譯器進行推斷的時候都將
  • 7 定義了一個方法井氢,傳入的是非空的參數(shù)String
  • 8 傳入的是非空的String值弦追,這里將不會報錯
  • 9 傳入的可為空的String? 值,這里將會報錯
    有時候你必須處理null值花竞,可能是因為Java代碼傳入了null 也可能是null代表了一種狀態(tài)劲件,這時候kotlin提供了一種處理null的方法
fun describeString(maybeString: String?): String {              // 1
    if (maybeString != null && maybeString.length > 0) {        // 2
        return "String of length ${maybeString.length}"
    } else {
        return "Empty or null string"                           // 3
    }
}
  • 1 定義了一個方法可入可為空的String 類型,返回一個不可為空的String類型
  • 2 判斷maybeString 是否為空或者為空字符串约急,如果是就返回maybeString的長度
  • 3 不然的話就告知調(diào)用者零远,傳入的參數(shù)為空或者為空字符串

定義由類名,類頭(包含類型聲明厌蔽,私有構(gòu)造方法等)牵辣、和類體組成,并且由大括號組成奴饮。類頭和類體都是可以缺省的服猪。如果類體缺省供填,那么大括號也可以缺省。

class Customer                                  // 1

class Contact(val id: Int, var email: String)   // 2

fun main() {

    val customer = Customer()                   // 3
    
    val contact = Contact(1, "mary@gmail.com")  // 4

    println(contact.id)                         // 5
    contact.email = "jane@gmail.com"            // 6
}
  • 1 定義一個類Customer 罢猪,這個類沒有定義任何屬性和構(gòu)造方法近她。 kotlin將會自動賦予一個無參構(gòu)造方法
  • 2 定義一個Contact 類,類里面有一個不可變變量的id膳帕,一個可變的變量email粘捎,并且有一個帶有兩個參數(shù)的構(gòu)造方法
  • 3 創(chuàng)建一個不可變的變量 實例customer類型推斷為Customer。使用Customer的默認構(gòu)造方法危彩。在kotlin中是沒有new關(guān)鍵字的
  • 4 創(chuàng)建一個Contact的實例攒磨,使用了帶有兩個參數(shù)的構(gòu)造方法
  • 5 讀取contact的屬性id
  • 6 更新contact的屬性email

泛型

泛型是現(xiàn)代語言都具有的一種模板方法。泛型類和泛型方法使得代碼具有高度的可復(fù)用性汤徽。就像List<T>里賣弄的內(nèi)部邏輯與T就沒有什么邏輯上的關(guān)系

泛型類

第一種使用泛型的方法就是泛型類

class MutableStack<E>(vararg items: E) {              // 1

  private val elements = items.toMutableList() 

  fun push(element: E) = elements.add(element)        // 2

  fun peek(): E = elements.last()                     // 3

  fun pop(): E = elements.removeAt(elements.size - 1)

  fun isEmpty() = elements.isEmpty()

  fun size() = elements.size

  override fun toString() = "MutableStack(${elements.joinToString()})"
}
  • 1 定義一個泛型類娩缰,E可以被稱為泛型參數(shù)。當(dāng)你定義MutableStack<Int> 的時候Int 就被稱呼為泛型參數(shù)
  • 2 在泛型類里面的方法中你可以用E來代替泛型參數(shù)
  • 3 你也可以用E來代替返回值
泛型方法

你當(dāng)然也可以定義泛型方法谒府,如果他們的邏輯與泛型參數(shù)無關(guān)的話拼坎。比如你可以定義一個這樣的方法

fun <E> mutableStackOf(vararg elements: E) = MutableStack(*elements)

fun main() {
  val stack = mutableStackOf(0.62, 3.14, 2.7)
  println(stack)
}

注意:編譯將會推斷出mutableStackOf是一個Double的MutableStack所以你不需要填寫mutableStackOf<Double>(...) 之類的


繼承

kotlin 支持傳統(tǒng)的面向?qū)ο蟮睦^承機制

open class Dog {                // 1
    open fun sayHello() {       // 2
        println("wow wow!")
    }
}

class Yorkshire : Dog() {       // 3
    override fun sayHello() {   // 4
        println("wif wif!")
    }
}

fun main() {
    val dog: Dog = Yorkshire()
    dog.sayHello()
}
  • 1 kotlin 的類默認是final的,如果你要允許類可以被繼承完疫,你需要添加 open 關(guān)鍵字到class 之前泰鸡。
  • 2 kotlin的方法默認也是final的,如果你要允許方法可以被重寫,你需要添加open關(guān)鍵字到fun 之前。
  • 3 一個子類應(yīng)該定義在: SuperclassName()之前夜牡。空的() 意味著super了父類的默認構(gòu)造方法余舶。
  • 4 重寫的方法胡總和屬性,應(yīng)該添加override 關(guān)鍵字
帶有參數(shù)的構(gòu)造方法的繼承
open class Tiger(val origin: String) {
    fun sayHello() {
        println("A tiger from $origin says: grrhhh!")
    }
}

class SiberianTiger : Tiger("Siberia")                  // 1

fun main() {
    val tiger: Tiger = SiberianTiger()
    tiger.sayHello()
}
  • 1 如果你想要用父類的構(gòu)造方法定義一個子類锹淌,那么你需要在定義的時候傳入傳給父類的字段欧芽。
傳遞參數(shù)給父類
open class Lion(val name: String, val origin: String) {
    fun sayHello() {
        println("$name, the lion from $origin says: graoh!")
    }
}

class Asiatic(name: String) : Lion(name = name, origin = "India") // 1

fun main() {
    val lion: Lion = Asiatic("Rufo")                              // 2
    lion.sayHello()
}
  • 1 Asiatic 類里的name 既不是val 也不是var。這是一個構(gòu)造方法的參數(shù)葛圃,只用來將值傳遞給父類的的構(gòu)造方法。
  • 2 用構(gòu)造參數(shù)Rufo創(chuàng)建一個Asiatic的實例憎妙,這個調(diào)用將會嗲用父類Lion 的雙參構(gòu)造方法
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末库正,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子厘唾,更是在濱河造成了極大的恐慌褥符,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,525評論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件抚垃,死亡現(xiàn)場離奇詭異喷楣,居然都是意外死亡趟大,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,203評論 3 395
  • 文/潘曉璐 我一進店門铣焊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來逊朽,“玉大人,你說我怎么就攤上這事曲伊∵椿洌” “怎么了?”我有些...
    開封第一講書人閱讀 164,862評論 0 354
  • 文/不壞的土叔 我叫張陵坟募,是天一觀的道長岛蚤。 經(jīng)常有香客問我,道長懈糯,這世上最難降的妖魔是什么涤妒? 我笑而不...
    開封第一講書人閱讀 58,728評論 1 294
  • 正文 為了忘掉前任,我火速辦了婚禮赚哗,結(jié)果婚禮上她紫,老公的妹妹穿的比我還像新娘。我一直安慰自己蜂奸,他們只是感情好犁苏,可當(dāng)我...
    茶點故事閱讀 67,743評論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著扩所,像睡著了一般围详。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上祖屏,一...
    開封第一講書人閱讀 51,590評論 1 305
  • 那天助赞,我揣著相機與錄音,去河邊找鬼袁勺。 笑死雹食,一個胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的期丰。 我是一名探鬼主播群叶,決...
    沈念sama閱讀 40,330評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼钝荡!你這毒婦竟也來了街立?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 39,244評論 0 276
  • 序言:老撾萬榮一對情侶失蹤埠通,失蹤者是張志新(化名)和其女友劉穎赎离,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體端辱,經(jīng)...
    沈念sama閱讀 45,693評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡梁剔,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,885評論 3 336
  • 正文 我和宋清朗相戀三年虽画,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片荣病。...
    茶點故事閱讀 40,001評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡码撰,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出众雷,到底是詐尸還是另有隱情灸拍,我是刑警寧澤,帶...
    沈念sama閱讀 35,723評論 5 346
  • 正文 年R本政府宣布砾省,位于F島的核電站鸡岗,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏编兄。R本人自食惡果不足惜轩性,卻給世界環(huán)境...
    茶點故事閱讀 41,343評論 3 330
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望狠鸳。 院中可真熱鬧揣苏,春花似錦、人聲如沸件舵。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,919評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽铅祸。三九已至坑质,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間临梗,已是汗流浹背涡扼。 一陣腳步聲響...
    開封第一講書人閱讀 33,042評論 1 270
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留盟庞,地道東北人吃沪。 一個月前我還...
    沈念sama閱讀 48,191評論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像什猖,于是被迫代替她去往敵國和親票彪。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,955評論 2 355