?????Kotlin已出現(xiàn)一段時(shí)間版述,很多同學(xué)都聽(tīng)過(guò)甚至寫過(guò)一些demo。在我入門時(shí)候總有一種盲人摸象不識(shí)大體的感覺(jué),如果恰好你也有這種感覺(jué),那么就一起探討下面的問(wèn)題吧:
?????What is Kotlin?-- Kotlin是什么嗅骄?
?????Why Kotlin?--Kotlin能給我們帶來(lái)什么?
???一饼疙、Kotlin是什么
??? Kotlin是一種Java系編程語(yǔ)言溺森。
???Java系編程語(yǔ)言指經(jīng)過(guò)編譯生成字節(jié)碼(Java byte code), 從而可在JVM上運(yùn)行的語(yǔ)言,也可以稱之為Java平臺(tái)語(yǔ)言。
??? 注意:Android 中的虛擬機(jī)并不是 JVM窑眯,而是Dalvik/ART屏积,需要用字節(jié)碼(Java byte code)進(jìn)行再一次轉(zhuǎn)換成相對(duì)應(yīng)的Dalvik字節(jié)碼。
???提問(wèn): 是否可以新創(chuàng)造一門語(yǔ)言磅甩,編譯的時(shí)候也生成字節(jié)碼炊林,然后在JVM 中運(yùn)行呢?這樣既能享受到 JVM 和成熟 Java 框架的各種好處更胖,還可以甩掉Java語(yǔ)言的不足之處铛铁,有很多自己新的特性隔显。
???回答: 當(dāng)然可以 H捶痢!比如Java 平臺(tái)已經(jīng)衍生出 Scala括眠、Clojure彪标、Groovy 等比較流行的語(yǔ)言了。而 Kotlin 則是Java平臺(tái)系語(yǔ)言中的新星掷豺,出自大名鼎鼎的JetBrains 公司捞烟。
???下面用一個(gè)圖來(lái)幫助我們了解下Java與Kotlin的編譯與執(zhí)行:
名詞解釋(大神請(qǐng)略過(guò))
Java source code : Java源代碼,就是我們根據(jù)Java 語(yǔ)言規(guī)范所編寫的源程序文件当船,擴(kuò)展名為.java题画。
Kotlin source code: Kotlin源代碼,就是我們根據(jù)Kotlin語(yǔ)言規(guī)范所編寫的源程序文件德频,擴(kuò)展名為.kt苍息。
Javac: 全稱Java compiler,是收錄于JDK中的Java語(yǔ)言編譯器壹置。該工具可以將后綴名為.java的源文件編譯成后綴名為.class的文件竞思,該文件包含著可以運(yùn)行于Java虛擬機(jī)的字節(jié)碼。
Kotlinc:全稱Kotlin compiler钞护,該工具可以將后綴名為.kt的源文件編譯成后綴名為.class的文件盖喷,該文件包含著可以運(yùn)行于Java虛擬機(jī)的字節(jié)碼。感興趣同學(xué)可以繼續(xù)研究Kotlinc用法
??? 可以在Android Studio->File->Settings->Plugins->Kotlin 看到Kotlin插件难咕,它就是Android開(kāi)發(fā)環(huán)境下的Kotlin編譯器课梳。
Java byte code: Java字節(jié)碼距辆,是Java虛擬機(jī)的(JVM)的指令集、存儲(chǔ)于.class文件中暮刃、可以用Javap等命令查看挑格。
JVM: Java Virtual Machine,縮寫為JVM沾歪,一種能夠運(yùn)行Java bytecode的虛擬機(jī)漂彤,JVM屏蔽了與具體操作系統(tǒng)平臺(tái)相關(guān)的信息,使得Java程序只需編譯生成可以在Java虛擬機(jī)上運(yùn)行的目標(biāo)代碼(Java字節(jié)碼)灾搏,就可以在多種平臺(tái)上不加修改地運(yùn)行挫望。
??????由于JVM并不是專為Java所實(shí)現(xiàn)的運(yùn)行時(shí),所以只要有編程語(yǔ)言的編譯器能生成正確Java bytecode文件狂窑,則這個(gè)語(yǔ)言也能實(shí)現(xiàn)在JVM上運(yùn)行媳板,比如我們本文主角Kotlin。
機(jī)器碼: Machine code是一種指令集泉哈,這種指令集是計(jì)算機(jī)的CPU可直接解讀懂的數(shù)據(jù)蛉幸,比如0000代表加載(LOAD)0001代表存儲(chǔ)(STORE)。
dx工具: Android Apk打包生成的過(guò)程丛晦,就是將.java文件轉(zhuǎn)換成.dex文件的過(guò)程奕纫。其中dx.bat就是將.class文件轉(zhuǎn)換為.dex文件的工具,在類似Android\Sdk\build-tools\28.0.3目錄下可以找到烫沙。
Dalvik: 類似JVM匹层,可以稱為Android虛擬機(jī),后綴為.dex(即“Dalvik Executable”)格式的Java應(yīng)用程序可以在其上運(yùn)行锌蓄。.dex格式是專為Dalvik設(shè)計(jì)的一種壓縮格式升筏,適合內(nèi)存和處理器速度有限的系統(tǒng)。
ART: Android Runtime瘸爽,在Android 5.0及后續(xù)Android版本中作為正式的運(yùn)行時(shí)庫(kù)取代了以往的Dalvik虛擬機(jī)您访。它與Dalvik的主要不同在于采用Ahead-of-time(AOT)技術(shù),那就是在安裝Apk時(shí)就把字節(jié)碼轉(zhuǎn)換為機(jī)器碼剪决,Dalvik是在運(yùn)行時(shí)候才把字節(jié)碼轉(zhuǎn)換為機(jī)器碼灵汪,所以ART有者更好的運(yùn)行時(shí)性能,但是有著安裝時(shí)間更長(zhǎng)昼捍、占用存儲(chǔ)空間更大的劣勢(shì)识虚。
第一章小結(jié)與問(wèn)題
??????從上文可以看出創(chuàng)造Kotlin語(yǔ)言最主要工作就是是創(chuàng)造一種新的編譯器Kotlinc,該編譯器主要作用是把符合Kotlin約定語(yǔ)法與結(jié)構(gòu)的源代碼解析為Java字節(jié)碼妒茬,從而可以在成熟的Java平臺(tái)上運(yùn)行担锤。
??????那么我們這里留下一些問(wèn)題給讀者:
??????Java源碼、Kotlin源碼和字節(jié)碼是否是一一對(duì)應(yīng)乍钻,為什么這樣設(shè)計(jì)肛循?
??????Java源碼和Kotlin源碼是否能夠利用工具實(shí)現(xiàn)完全轉(zhuǎn)換铭腕,如果可以原理是什么,如果不可以多糠,哪些地方不可以轉(zhuǎn)換累舷,原因是什么?
二 相對(duì)于Java夹孔,Kotlin給我們帶來(lái)哪些好處
1 Data class -類定義標(biāo)準(zhǔn)與簡(jiǎn)化
Data class是Kotlin發(fā)布時(shí)候用的標(biāo)題被盈,其實(shí)指類定義的標(biāo)準(zhǔn)與簡(jiǎn)化。
例如我們要寫一個(gè)學(xué)生類搭伤,有兩個(gè)成員變量 姓名和分?jǐn)?shù)只怎,java和Kotlin代碼如下:
上面Java和Kotlin定義作用上是等同的,我們可以看到Kotlin是多么的簡(jiǎn)潔怜俐,編譯器直接幫我們補(bǔ)充好身堡、set()、get()拍鲤、toString()贴谎、hashcode()等方法。我們利用工具反編譯Kotlin生成的apk得到季稳,剛才那句話經(jīng)過(guò)編譯器得到是下面的內(nèi)容(注 只貼了一部分)
可以看到Kotlin編譯器自動(dòng)幫我們生成了構(gòu)造函數(shù)擅这、copy()、get()绞幌、set()等方法蕾哟。
2 Extension Functions-類功能擴(kuò)展
類擴(kuò)展可以幫助我們擴(kuò)展已有的 Class,而無(wú)需繼承這個(gè) Class莲蜘,無(wú)論我們能不能訪問(wèn)源碼。這對(duì)于系統(tǒng) Class 以及一些第三方 library 中的 Class 特別有幫助帘营。例如
我們擴(kuò)展Int 類票渠,讓Int類多出來(lái)一個(gè)方法getNext(),然后我們?cè)谖覀兊墓こ汤锩娑伎梢允褂眠@個(gè)方法芬迄。那么有同學(xué)就會(huì)想是否有大神把一些常用的擴(kuò)展封裝成庫(kù)給我們问顷,恰好Google也做了,Jetpack -這個(gè)里面就包含一些常用的類擴(kuò)展功能禀梳、感興趣的同學(xué)可以去研究下杜窄。
3 Null Safety-空指針檢查
Kotlin 中允許定義變量時(shí)可以指定它為可空類型(Nullable Type)和不可空類型(Non-Null Type),默認(rèn)是不可空類型算途。
4 Coroutines-協(xié)程
Coroutines: Co -合作+ routine-程序 -》Coroutines=合作的子程序集合塞耕,協(xié)程的誕生是為了解決子程序間合作與調(diào)度的問(wèn)題,本質(zhì)上協(xié)程和Rxjava 都是一個(gè)調(diào)度線程的API庫(kù)嘴瓤。
協(xié)程定義理解
??????子程序間合作問(wèn)題最主要難點(diǎn)在于異步與回調(diào)扫外。比如有兩個(gè)程序A-下載圖片莉钙,B-顯示圖片,流行處理方法就是開(kāi)啟一個(gè)線程去下載圖片筛谚、下載成功后通知在UI線程中的程序B運(yùn)行顯示圖片磁玉,這里我們需要自己寫開(kāi)啟線程、接口回調(diào)代碼驾讲、更不要說(shuō)去考慮線程數(shù)量蚊伞、切換代價(jià)等。而有了協(xié)程之后吮铭,它的內(nèi)部庫(kù)會(huì)封裝異步操作厚柳、回調(diào)、訂閱等沐兵,使各個(gè)子程序在不同線程上調(diào)度執(zhí)行别垮,而代碼則可以寫的保持如同順序執(zhí)行一樣簡(jiǎn)單。
??????所以我們可以認(rèn)為協(xié)程是一種特殊的子程序集扎谎,它可以在一個(gè)子程序中中斷碳想,去執(zhí)行其它子程序,不是函數(shù)調(diào)用毁靶,有點(diǎn)類似于CPU的中斷胧奔。
下面用一幅圖來(lái)形象的幫助我們理解進(jìn)程、線程與協(xié)程的關(guān)系
形象映射
生產(chǎn)車間:計(jì)算機(jī)中CPU等硬件資源是有限的,每個(gè)CPU單一時(shí)間只能運(yùn)行一個(gè)線程拐叉。所以我們可以把CUP等硬件資源當(dāng)做是正在生產(chǎn)中的車間岩遗,車間里面放置著用于生產(chǎn)的原材料和組裝好的正在進(jìn)行生產(chǎn)的產(chǎn)線;為了方便理解凤瘦、假設(shè)我們的資源非常有限宿礁,只有一個(gè)車間、車間內(nèi)只能開(kāi)動(dòng)兩條生產(chǎn)線(雙核CPU)蔬芥。
車間搭建資源:車間想持續(xù)產(chǎn)出梆靖,不僅需要著用于生產(chǎn)的原材料、還要有搭建好的產(chǎn)線笔诵。車間搭建的資源就是在倉(cāng)庫(kù)中堆積著的原材料返吻、設(shè)備與搭建方案文案、一旦決定生產(chǎn)何種產(chǎn)品乎婿,那就從倉(cāng)庫(kù)中取出這這些資源测僵,按照搭建方案把設(shè)備組裝成產(chǎn)線、放置好原材料次酌,通上電開(kāi)始生產(chǎn)恨课。車間搭建資源就相當(dāng)于進(jìn)程舆乔。
??????每一個(gè)車間搭建資源(進(jìn)程)都是要占用倉(cāng)庫(kù)不少位置的,所以倉(cāng)庫(kù)越大(存儲(chǔ)容量越大)就可以有更多的進(jìn)程剂公、對(duì)應(yīng)手機(jī)就是存儲(chǔ)越大可以安裝APP更多希俩。
??????因?yàn)椴煌囬g搭建資源只有在裝載在車間中實(shí)際生產(chǎn)運(yùn)行時(shí)候才是活動(dòng)的,所以他們(進(jìn)程)想進(jìn)行交流通信纲辽,就是建立一個(gè)與車間無(wú)關(guān)的公共區(qū)域颜武、這些車間搭建資源可以在他們運(yùn)行時(shí)候都去該區(qū)域放東西或者拿東西,實(shí)現(xiàn)資源的交換拖吼。用計(jì)算機(jī)專業(yè)術(shù)語(yǔ)講講就是通過(guò)共享內(nèi)存實(shí)現(xiàn)進(jìn)程間通信鳞上。
車間選擇(切換):把當(dāng)前方案所需的原材料拿掉換上新的原材料、把當(dāng)前產(chǎn)線拆掉吊档,再組裝新的產(chǎn)線篙议。相當(dāng)于進(jìn)程切換,進(jìn)程切換=原料更換+產(chǎn)線重建怠硼。
產(chǎn)線:每條產(chǎn)線可以通過(guò)調(diào)整參數(shù)鬼贱、原材料進(jìn)行不同的產(chǎn)品加工、相當(dāng)于線程香璃。
產(chǎn)線切換:拆掉原來(lái)的產(chǎn)線这难、根據(jù)新的產(chǎn)線方案來(lái)重組新的產(chǎn)線,相當(dāng)于線程切換;
場(chǎng)景切換器:控制并實(shí)施車間和產(chǎn)線切換的部門葡秒,相當(dāng)于操作系統(tǒng)的Kernel(內(nèi)核)姻乓。我們需要在資源有限的情況下實(shí)現(xiàn)利益最大化,但幾條產(chǎn)線的產(chǎn)品具有相互依賴性并且外部對(duì)產(chǎn)品的需求一直也在變化中眯牧,那么如何根據(jù)外界環(huán)境變化最優(yōu)的安排不同的產(chǎn)線與生產(chǎn)方案蹋岩,正是kernel考慮的一個(gè)很重要問(wèn)題,調(diào)度算法炸站。
任務(wù)控制流:一系列生產(chǎn)任務(wù)(用戶添加)并且有內(nèi)置的調(diào)度機(jī)制星澳,該機(jī)制可以控制決定自己每一個(gè)子任務(wù)在哪條加工線運(yùn)行,并且按照順序執(zhí)行旱易,相當(dāng)于協(xié)程。 從這個(gè)方向看協(xié)程可以理解為一套線程調(diào)度的 API腿堤。
??????任務(wù)控制流中每個(gè)黑色的箭頭代表一個(gè)子任務(wù)阀坏,任務(wù)控制流,可以控制子任務(wù)暫停執(zhí)行笆檀,開(kāi)始執(zhí)行忌堂、并可以安排每個(gè)子任務(wù)在不同生產(chǎn)線上完成,這個(gè)相當(dāng)于協(xié)程切換酗洒,具體協(xié)程切換如下:
1 保存當(dāng)前協(xié)程的上下文(運(yùn)行棧士修,返回地址枷遂,寄存器狀態(tài));
2 設(shè)置將要喚醒的協(xié)程的入口指令地址到IP寄存器棋嘲;
3 恢復(fù)將要喚醒的協(xié)程的上下文酒唉。
發(fā)現(xiàn)與思考
切換代價(jià):進(jìn)程切換>線程切換>協(xié)程切換
??????進(jìn)程切換相當(dāng)于重新把當(dāng)前車間所有東西搬走,按照新的車間搭建方案重新搭建車間和產(chǎn)線沸移,需要搬運(yùn)痪伦、擺放原材料、寫生產(chǎn)小結(jié)雹锣、重新組裝原材料网沾。
??????線程切換相當(dāng)于新組裝一個(gè)產(chǎn)線,因?yàn)樾庐a(chǎn)線需要的各種資源蕊爵,已經(jīng)取出來(lái)在車間內(nèi)辉哥,所以只需要把不需要的產(chǎn)線拆卸掉,重新組裝新的產(chǎn)線就好攒射,無(wú)需搬運(yùn)生產(chǎn)資料醋旦,如果當(dāng)前產(chǎn)線比較少,甚至不需要拆卸產(chǎn)線匆篓,直接組裝新產(chǎn)線就好浑度。
??????協(xié)程切換相當(dāng)于內(nèi)部的任務(wù)調(diào)度,產(chǎn)線無(wú)需拆卸重組鸦概,只是調(diào)整一些參數(shù)就可以運(yùn)行不同的任務(wù)箩张, 我們還可以看到協(xié)程是自己控制,非操作系統(tǒng)kernel控制窗市。
進(jìn)程先慷、線程、協(xié)程限制: 車間有限咨察,所以進(jìn)程有限论熙,在當(dāng)前只有一個(gè);線程在車間內(nèi)摄狱,創(chuàng)建線程也需要各種資源脓诡、車間大小也有限,所以線程也有限媒役;協(xié)程祝谚,原則上只是一種任務(wù)調(diào)度機(jī)制,大部分以文檔形式存在酣衷,所需要的資源都是線程的交惯,所以限制很少,可以創(chuàng)建很多很多協(xié)程。
協(xié)程掛起: 任務(wù)控制流發(fā)現(xiàn)它控制的任務(wù)A需要的材料不足席爽,那么它就說(shuō)先暫停這個(gè)子生產(chǎn)任務(wù)意荤,但生產(chǎn)線可以繼續(xù)工作,把A需要的材料生產(chǎn)出來(lái)A再繼續(xù)工作只锻。
協(xié)程調(diào)度: 從上面可以知道玖像,協(xié)程有兩個(gè)重要的部分1 子程序集 2 調(diào)度機(jī)制。調(diào)度機(jī)制是協(xié)程不同于子程序的關(guān)鍵炬藤。下面簡(jiǎn)單說(shuō)下協(xié)程的調(diào)度器:
??????CoroutineDispatcher御铃,協(xié)程調(diào)度器,決定協(xié)程所在的線程或線程池沈矿。它可以指定協(xié)程運(yùn)行于特定的一個(gè)線程上真、一個(gè)線程池或者不指定任何線程(這樣協(xié)程就會(huì)運(yùn)行于當(dāng)前線程)。coroutines-core中 CoroutineDispatcher 有三種標(biāo)準(zhǔn)實(shí)現(xiàn)Dispatchers.Default羹膳、Dispatchers.IO睡互,Dispatchers.Main和Dispatchers.Unconfined,Unconfined 就是不指定線程陵像。
??????launch函數(shù)定義如果不指定CoroutineDispatcher或者沒(méi)有其他的ContinuationInterceptor就珠,默認(rèn)的協(xié)程調(diào)度器就是Dispatchers.Default,Default是一個(gè)協(xié)程調(diào)度器醒颖,其指定的線程為共有的線程池妻怎,線程數(shù)量至少為 2 最大與 CPU 數(shù)相同。
協(xié)程原理
??????從上面可以看出泞歉,協(xié)程主要作用解決不同子程序調(diào)度問(wèn)題逼侦,它會(huì)封裝異步操作、回調(diào)腰耙、訂閱等榛丢,使我們的程序在不同線程上調(diào)度執(zhí)行,而代碼則可以寫的保持如同順序執(zhí)行一樣挺庞。如果這種事是我們自己來(lái)做呢晰赞?其實(shí)我們也很容易想到設(shè)定一個(gè)全局的變量,然后不同的協(xié)作任務(wù)都能改變這個(gè)變量的狀態(tài)选侨,然后根據(jù)變量的狀態(tài)值掖鱼,來(lái)決定調(diào)度哪一個(gè)子程序,這叫Switch狀態(tài)機(jī)援制,協(xié)程也是這樣做的锨用,總結(jié)下就是狀態(tài)機(jī)+回調(diào)=協(xié)程調(diào)度。感興趣同學(xué)可以閱讀協(xié)程原理解析
協(xié)程與RxJava
??????功能類似隘谣、實(shí)現(xiàn)不同,協(xié)程寫法更具有可閱讀性,協(xié)程具體實(shí)現(xiàn)也更高效寻歧,感興趣同學(xué)可以看搜關(guān)鍵字RxJava與協(xié)程掌栅,多看幾篇。
其他注意事項(xiàng)
頂層方法定義
在kotlin中方法是可以獨(dú)立于類的码泛,我們可以像上圖一樣定義方法猾封,然后全局調(diào)用,默認(rèn)方法都是public噪珊。
Kotlin lambda
閱讀Kotlin源碼時(shí)候晌缘,會(huì)遇到lambda表達(dá)式,kotlin中對(duì)于lambda有很多簡(jiǎn)化的約定:
1 如果lambda表達(dá)式是函數(shù)調(diào)用的最后一個(gè)實(shí)參痢站,它可以放在括號(hào)外面磷箕;
2 當(dāng)lambda是函數(shù)唯一的實(shí)參時(shí),可以去掉函數(shù)調(diào)用的括號(hào)阵难;
3 如果lambda的參數(shù)的類型可以推導(dǎo)岳枷,那么可以省略參數(shù)的類型;
4 對(duì)于lambda中一個(gè)參數(shù)時(shí)呜叫,可以使用默認(rèn)參數(shù)名稱it來(lái)代替命名參數(shù)空繁,并且lambda的參數(shù)列表可以簡(jiǎn)化,省略參數(shù)列表和->朱庆。
Kotlin to JS
第二章小結(jié)與Kotlin啟示
??????Kotlin語(yǔ)言為解決Java語(yǔ)言的問(wèn)題而生傲诵,它提供了類的標(biāo)準(zhǔn)定義與簡(jiǎn)化、類的方法擴(kuò)展维蒙、空指針檢查掰吕、協(xié)程等用戶(工程師)友好的功能,這些都是把用戶經(jīng)常需要做和必須做的工作抽取出來(lái)提供標(biāo)準(zhǔn)化和自動(dòng)化的解決方案颅痊,從而減少用戶的工作量殖熟,這屬于AI思維。
??????AI思維是通過(guò)把重復(fù)斑响、規(guī)律的事交給人工智能來(lái)成降低成本菱属,本質(zhì)是標(biāo)準(zhǔn)化和量化思維! 當(dāng)一件事情可以標(biāo)準(zhǔn)化和量化舰罚,我們便能夠實(shí)現(xiàn)可復(fù)制的成功纽门。
參考文獻(xiàn)
Kotlin中文學(xué)習(xí)網(wǎng)站 http://www.kotlincn.net/docs/reference/
協(xié)程理解:http://www.reibang.com/p/2979732fb6fb