給Java程序員的Kotlin介紹信

     Kotlin已出現一段時間,很多同學都聽過甚至寫過一些demo。在我入門時候總有一種盲人摸象不識大體的感覺,如果恰好你也有這種感覺,那麼就一起探討下面的問題吧:
     What is Kotlin?-- Kotlin是什麼?
     Why Kotlin?--Kotlin能給我們帶來什麼?

   一、Kotlin是什麼

    Kotlin是一種Java系編程語言。

   Java系編程語言指經過編譯生成字節碼(Java byte code), 從而可在JVM上運行的語言,也可以稱之爲Java平臺語言。

    注意:Android 中的虛擬機並不是 JVM,而是Dalvik/ART,需要用字節碼(Java byte code)進行再一次轉換成相對應的Dalvik字節碼。

   提問: 是否可以新創造一門語言,編譯的時候也生成字節碼,然後在JVM 中運行呢?這樣既能享受到 JVM 和成熟 Java 框架的各種好處,還可以甩掉Java語言的不足之處,有很多自己新的特性。

   回答: 當然可以 !!比如Java 平臺已經衍生出 Scala、Clojure、Groovy 等比較流行的語言了。而 Kotlin 則是Java平臺系語言中的新星,出自大名鼎鼎的JetBrains 公司。

   下面用一個圖來幫助我們瞭解下Java與Kotlin的編譯與執行:


名詞解釋(大神請略過)

Java source code : Java源代碼,就是我們根據Java 語言規範所編寫的源程序文件,擴展名爲.java。
Kotlin source code: Kotlin源代碼、就是我們根據Kotlin語言規範所編寫的源程序文件,擴展名爲.kt。
Javac: 全稱Java compiler ,是收錄於JDK中的Java語言編譯器。該工具可以將後綴名爲.java的源文件編譯成後綴名爲.class的文件,該文件包含着可以運行於Java虛擬機的字節碼。
Kotlinc:全稱Kotlin compiler 。該工具可以將後綴名爲.kt的源文件編譯成後綴名爲.class的文件,該文件包含着可以運行於Java虛擬機的字節碼。感興趣同學可以繼續研究Kotlinc用法
    可以在Android Studio->File->Settings->Plugins->Kotlin 看到Kotlin插件,它就是Android開發環境下的Kotlin編譯器。
Java byte code Java字節碼,是Java虛擬機的(JVM)的指令集、存儲於.class文件中、可以用Javap等命令查看。
JVM: Java Virtual Machine,縮寫爲JVM,一種能夠運行Java bytecode的虛擬機,JVM屏蔽了與具體操作系統平臺相關的信息,使得Java程序只需生成在Java虛擬機上運行的目標代碼(字節碼),就可以在多種平臺上不加修改地運行。
      由於JVM並不是專爲Java所實現的運行時,所以只要有編程語言的編譯器能生成正確Java bytecode文件,則這個語言也能實現在JVM上運行,比如我們本文主角Kotlin。
機器碼: Machine code是一種指令集,這種指令集是計算機的CPU可直接解讀懂的數據,比如0000代表加載(LOAD)0001代表存儲(STORE)。
dx工具: Android Apk打包生成的過程,就是將.java文件轉換成.dex文件的過程。其中dx.bat就是將.class文件轉換爲.dex文件的工具,在類似Android\Sdk\build-tools\28.0.3目錄下可以找到。
Dalvik 類似JVM,可以稱爲Android虛擬機,後綴爲.dex(即“Dalvik Executable”)格式的Java應用程序可以在其上運行。.dex格式是專爲Dalvik設計的一種壓縮格式,適合內存和處理器速度有限的系統。
ART Android Runtime,在Android 5.0及後續Android版本中作爲正式的運行時庫取代了以往的Dalvik虛擬機。它與Dalvik的主要不同在於採用Ahead-of-time(AOT)技術,那就是在安裝Apk時就把字節碼轉換爲機器碼,Dalvik是在運行時候才把字節碼轉換爲機器碼,所以ART有者更好的運行時性能、但是有着安裝時間更長、佔用存儲空間更大的劣勢。

第一章小結與問題

      從上文可以看出創造Kotlin語言最主要工作就是是創造一種新的編譯器Kotlinc,該編譯器主要作用是把符合Kotlin約定語法與結構的源代碼解析爲Java字節碼,從而可以在成熟的Java平臺上運行。
      那麼我們這裏留下一些問題給讀者:
      Java源碼、Kotlin源碼和字節碼是否是一一對應,爲什麼這樣設計?
      Java源碼和Kotlin源碼是否能夠利用工具實現完全轉換,如果可以原理是什麼,如果不可以,哪些地方不可以轉換,原因是什麼?

二 相對於Java,Kotlin給我們帶來哪些好處

1 Data class -類定義標準與簡化

Data class是Kotlin發佈時候用的標題,其實指類定義的標準與簡化。
例如我們要寫一個學生類,有兩個成員變量 姓名和分數,java和Kotlin代碼如下:


上面Java和Kotlin定義作用上是等同的,我們可以看到Kotlin是多麼的簡潔,編譯器直接幫我們補充好、set()、get()、toString()、hashcode()等方法。我們利用工具反編譯Kotlin生成的apk得到,剛纔那句話經過編譯器得到是下面的內容(注 只貼了一部分)




可以看到Kotlin編譯器自動幫我們生成了構造函數、copy()、get()、set()等方法。

2 Extension Functions-類功能擴展

類擴展可以幫助我們擴展已有的 Class,而無需繼承這個 Class,無論我們能不能訪問源碼。這對於系統 Class 以及一些第三方 library 中的 Class 特別有幫助。例如



我們擴展Int 類,讓Int類多出來一個方法getNext(),然後我們在我們的工程裏面都可以使用這個方法。那麼有同學就會想沒有大神把一些常用的擴展封裝成庫給我們,恰好Google也做了,Jetpack -這個裏面就包含一些常用的類擴展功能、感興趣的同學可以去研究下。

3 Null Safety-空指針檢查

Kotlin 中允許定義變量時可以指定它爲可空類型(Nullable Type)和不可空類型(Non-Null Type),默認是不可空類型。


4 Coroutines-協程

Coroutines: Co -合作+ routine-程序 -》Coroutines=合作的子程序集合,協程的誕生是爲了解決子程序間合作與調度的問題。

協程定義理解

      子程序間合作問題最主要難點在於異步與回調。比如有兩個程序A-下載圖片,B-顯示圖片,流行處理方法就是開啓一個線程去下載圖片、下載成功後通知在UI線程中的程序B運行顯示圖片,這裏我們需要自己寫開啓線程、接口回調代碼、更不要說去考慮線程數量、切換代價等。而有了協程之後,它的內部庫會封裝異步操作、回調、訂閱等,使各個子程序在不同線程上調度執行,而代碼則可以寫的保持如同順序執行一樣簡單。
      所以我們可以認爲協程是一種特殊的子程序集,它可以在一個子程序中中斷,去執行其它子程序,不是函數調用,有點類似於CPU的中斷。
下面用一幅圖來形象的幫助我們理解進程、線程與協程的關係

形象映射

生產車間:計算機中CPU等硬件資源是有限的,每個CPU單一時間只能運行一個線程。所以我們可以把CUP等硬件資源當做是正在生產中的車間,車間裏面放置着用於生產的原材料和組裝好的正在進行生產的產線;爲了方便理解、假設我們的資源非常有限,只有一個車間、車間內只能開動兩條生產線(雙核CPU)。

車間搭建資源:車間想持續產出,不僅需要着用於生產的原材料、還要有搭建好的產線。車間搭建的資源就是在倉庫中堆積着的原材料、設備與搭建方案文案、一旦決定生產何種產品,那就從倉庫中取出這這些資源,按照搭建方案把設備組裝成產線、放置好原材料,通上電開始生產。車間搭建資源就相當於進程
      每一個車間搭建資源(進程)都是要佔用倉庫不少位置的,所以倉庫越大(存儲容量越大)就可以有更多的進程、對應手機就是存儲越大可以安裝APP更多。
      因爲不同車間搭建資源只有在裝載在車間中實際生產運行時候纔是活動的,所以他們(進程)想進行交流通信,就是建立一個與車間無關的公共區域、這些車間搭建資源可以在他們運行時候都去該區域放東西或者拿東西,實現資源的交換。用計算機專業術語講講就是通過共享內存實現進程間通信。

車間選擇(切換):把當前方案所需的原材料拿掉換上新的原材料、把當前產線拆掉,再組裝新的產線。相當於進程切換,進程切換=原料更換+產線重建

產線:每條產線可以通過調整參數、原材料進行不同的產品加工、相當於線程。

產線切換:拆掉原來的產線、根據新的產線方案來重組新的產線,相當於線程切換;

場景切換器:控制並實施車間和產線切換的部門,相當於操作系統的Kernel(內核)。我們需要在資源有限的情況下實現利益最大化,但幾條產線的產品具有相互依賴性並且外部對產品的需求一直也在變化中,那麼如何根據外界環境變化最優的安排不同的產線與生產方案,正是kernel考慮的一個很重要問題,調度算法。

任務控制流:一系列生產任務(用戶添加)並且有內置的調度機制,該機制可以控制決定自己每一個子任務在哪條加工線運行,並且按照順序執行,相當於協程
      任務控制流中每個黑色的箭頭代表一個子任務,任務控制流,可以控制子任務暫停執行,開始執行、並可以安排每個子任務在不同生產線上完成,這個相當於協程切換,具體協程切換如下:
1 保存當前協程的上下文(運行棧,返回地址,寄存器狀態);
2 設置將要喚醒的協程的入口指令地址到IP寄存器;
3 恢復將要喚醒的協程的上下文。

發現與思考

切換代價:進程切換>線程切換>協程切換
      進程切換相當於重新把當前車間所有東西搬走,按照新的車間搭建方案重新搭建車間和產線,需要搬運、擺放原材料、寫生產小結、重新組裝原材料。
      線程切換相當於新組裝一個產線,因爲新產線需要的各種資源,已經取出來在車間內,所以只需要把不需要的產線拆卸掉,重新組裝新的產線就好,無需搬運生產資料,如果當前產線比較少,甚至不需要拆卸產線,直接組裝新產線就好。
      協程切換相當於內部的任務調度,產線無需拆卸重組,只是調整一些參數就可以運行不同的任務, 我們還可以看到協程是自己控制,非操作系統kernel控制。

進程、線程、協程限制: 車間有限,所以進程有限,在當前只有一個;線程在車間內,創建線程也需要各種資源、車間大小也有限,所以線程也有限;協程,原則上只是一種任務調度機制,大部分以文檔形式存在,所需要的資源都是線程的,所以限制很少,可以創建很多很多協程。

協程掛起: 任務控制流發現它控制的任務A需要的材料不足,那麼它就說先暫停這個子生產任務,但生產線可以繼續工作,把A需要的材料生產出來A再繼續工作。

協程調度: 從上面可以知道,協程有兩個重要的部分1 子程序集 2 調度機制。調度機制是協程不同於子程序的關鍵。下面簡單說下協程的調度器:
      CoroutineDispatcher,協程調度器,決定協程所在的線程或線程池。它可以指定協程運行於特定的一個線程、一個線程池或者不指定任何線程(這樣協程就會運行於當前線程)。coroutines-core中 CoroutineDispatcher 有三種標準實現Dispatchers.Default、Dispatchers.IO,Dispatchers.Main和Dispatchers.Unconfined,Unconfined 就是不指定線程。
      launch函數定義如果不指定CoroutineDispatcher或者沒有其他的ContinuationInterceptor,默認的協程調度器就是Dispatchers.Default,Default是一個協程調度器,其指定的線程爲共有的線程池,線程數量至少爲 2 最大與 CPU 數相同。

協程原理

      從上面可以看出,協程主要作用解決不同子程序調度問題,它會封裝異步操作、回調、訂閱等,使我們的程序在不同線程上調度執行,而代碼則可以寫的保持如同順序執行一樣。如果這種事是我們自己來做呢?其實我們也很容易想到設定一個全局的變量,然後不同的協作任務都能改變這個變量的狀態,然後根據變量的狀態值,來決定調度哪一個子程序,這叫Switch狀態機,協程也是這樣做的,總結下就是狀態機+回調=協程調度。感興趣同學可以閱讀協程原理解析

協程與RxJava

      功能類似、實現不同,協程寫法更具有可閱讀性,協程具體實現也更高效,感興趣同學可以看搜關鍵字RxJava與協程,多看幾篇。

其他注意事項

頂層方法定義


在kotlin中方法是可以獨立於類的,我們可以像上圖一樣定義方法,然後全局調用,默認方法都是public。

Kotlin lamba

閱讀Kotlin源碼時候,會遇到lamba表達式,kotlin中對於lambda有很多簡化的約定:
1 如果lambda表達式是函數調用的最後一個實參,它可以放在括號外面;
2 當lambda是函數唯一的實參時,可以去掉函數調用的括號;
3 如果lambda的參數的類型可以推導,那麼可以省略參數的類型;
4 對於lambda中一個參數時,可以使用默認參數名稱it來代替命名參數,並且lambda的參數列表可以簡化,省略參數列表和->。

第二章小結與Kotlin啓示

      Kotlin語言爲解決Java語言的問題而生,它提供了類的標準定義與簡化、類的方法擴展、空指針檢查、協程等用戶(工程師)友好的功能,這些都是把用戶經常需要做和必須做的工作抽取出來提供標準化和自動化的解決方案,從而減少用戶的工作量,這屬於AI思維。
      AI思維是通過把重複、規律的事交給人工智能來成降低成本,本質是標準化和量化思維! 當一件事情可以標準化和量化,我們便能夠實現可複製的成功

參考文獻

Kotlin中文學習網站 http://www.kotlincn.net/docs/reference/
協程理解:https://www.jianshu.com/p/2979732fb6fb

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章