Kotlin是JetBrains在2011年推出的一門全新的編程語言,這門語言*早被設計成運行在JVM上使用Kotlin編寫的程序會被編譯成字節碼文件,該字節碼文件可直接在JVM上運行(用java,命令運行)。目前Google已推薦使用Kotlin作為Android的官方開發語言,這意味著Kotlin將會在Android開發上大放異彩。本書全面介紹了Kotlin的語法。從各平臺上Kotlin程序的編譯、運行開始介紹,詳細介紹了Kotlin的基本語法,Kotlin的數組和集合,Kotlin函數式編程特征,Kotlin的面向對象編程、異常處理、泛型和注解,還介紹了Kotlin與Java混合調用的相關內容,以及Kotlin反射相關內容。本書對Kotlin的解讀十分系統、全面,超過Kotlin官方文檔本身覆蓋的內容。本書很多地方都會結合Java字節碼進行深入解讀,比如對Kotlin擴展的解讀,對Kotlin主、次構造器的解讀,這種解讀目的不止于教會讀者簡單地掌握Kotlin的用法,而是力求讓讀者深入理解Kotlin,且更好地理解Java。簡單來說,本書不僅是一本Kotlin的學習圖書,而且也是一本能讓你更深入地理解Java的圖書。如果讀者在閱讀本書時遇到了技術問題,可以登錄瘋狂Java聯盟(http://www.crazyit.org)發帖,筆者將會及時予以解答。
1.邏輯結構更合理
《瘋狂Kotlin講義》在內容體系上將函數式編程和面向對象編程獨立開來,先介紹函數式編程部分,再介紹面向對象編程,更符合Kotlin語言本身的知識體系。而不像某些資料一會兒函數,一會兒面向對象,攪得讀者暈頭轉向。實際上,無論是經典的圖書如《C Primer》,還是Swift官方文檔(甚至Kotlin官方文檔),幾乎都沒見過一會兒函數、一會兒面向對象這樣介紹的。
另外,整本書的知識具有和《瘋狂Java講義》大致相同的脈絡,所以《瘋狂Java講義》的讀者會很容易上手。
2.講解深入本質
Kotlin是JVM語言,所以其很多東西其實是受到Java的影響的。書中會對一些看似奇怪的語法從字節碼文件層次進行剖析,讓讀者更好地理解Kotlin與Java的對應關系。
3.知識內容更全面
《瘋狂Kotlin講義》內容超過Kotlin官方文檔本身所覆蓋的知識,比如介紹反射的章節就超過了Kotlin官方文檔內容。《瘋狂Kotlin講義》反射部分不僅更詳細地介紹如何獲得類、函數、屬性的引用,而且真正從API級別介紹KClass、KCallable、KFunction、KProperty,KProperty0、KProperty1、KProperty2的用法,以及它們的內在關聯,并實實在在地教讀者掌握如何用Kotlin反射動態創建對象、動態調用方法。
前 言
Kotlin是JetBrains在2011年推出的一門全新的編程語言,這門語言最早被設計成運行在JVM上使用Kotlin編寫的程序會被編譯成字節碼文件,該字節碼文件可直接在JVM上運行(用java命令運行即可)。Kotlin可以與現有的Java語言包保持完全兼容,而且Kotlin代碼比Java代碼更簡潔。Kotlin增加了擴展、對象表達式、對象聲明、委托等Java原本不支持的功能,它們都是現代編程語言廣泛支持的功能,并且完全可以在JVM上運行。
簡單來說,Kotlin既可利用Java的優勢,又比Java更簡潔。
Kotlin與現有的Java語言包保持完全兼容,這意味著Kotlin不是一門簡單的語言,它完全可以利用Java領域現有的各種工具和框架,如Spring、Hibernate、MyBatis、Lucene、Hadoop、Spring Cloud等。Kotlin可以直接使用它們,因此現有的Java項目完全可以采用Kotlin開發,Java開發者也很容易過渡到Kotlin。
不得不說的一點是,目前Android已推薦使用Kotlin作為官方開發語言,這意味著Kotlin將會在Android開發上大放異彩,這也是筆者決定向大家介紹這門語言的重要原因之一。
此外,Kotlin程序還可直接編譯生成JavaScript代碼,Kotlin程序既可編譯成前端JavaScript代碼,用于實現網頁的DOM操作,實現前端編程;也可編譯成后端JavaScript代碼,與服務端技術(如Node.js)交互。
需要指出的是,雖然Kotlin提供了簡潔的語法,但Kotlin的功能并不簡單,Kotlin從來就不是為了更簡單而設計的,而是為了更強大而設計的。Kotlin既支持函數式編程方式,也支持面向對象編程方式。Kotlin的函數式編程方式完全支持主流的函數和閉包,語法功能非常豐富。
可以這么說:Java支持的各種語法功能,Kotlin基本都支持;Java不支持的很多現代編程語言所具有的特征,Kotlin也支持,因此Kotlin絕不比Java更簡單。如果讀者相信網絡上某些所謂大神膚淺的結論:Kotlin很簡單,那么我建議你放棄閱讀這本書。
本書有什么特點
本書對Kotlin的解讀十分全面、深入,并非一本簡單介紹Kotlin語法的圖書,在很多地方都會結合Java語法、底層字節碼進行講解。如果讀者有較好的Java功底,閱讀本書能更清晰地看清Java與Kotlin之間的差異,便于快速上手Kotlin;對于沒有Java功底的讀者,可選擇忽略將二者進行對比的部分,直接學習本書也可掌握Kotlin語言的編程。
由于Kotlin最先被設計成運行在JVM平臺上的編程語言,因此Kotlin具有和Java天然的相似性,但在Java設計不足的地方又做了大量的補充、改進,所以本書也能讓你更好地理解Java,以及更好地理解Java存在的一些不足。這樣說并不代表Java不優秀,知其雄,守其雌,為天下谿,只有深入理解Java,才能更好地感悟Java的優秀。
總結起來,本書有如下幾個特點。
1.邏輯結構更合理
本書在內容體系上將函數式編程和面向對象編程獨立開來,先介紹函數式編程部分,再介紹面向對象編程,更符合Kotlin語言本身的知識體系。而不像某些資料一會兒函數,一會兒面向對象,攪得讀者暈頭轉向。實際上,無論是經典的圖書如《C Primer》,還是Swift官方文檔(甚至Kotlin官方文檔),幾乎都沒見過一會兒函數、一會兒面向對象這樣介紹的。
在介紹知識時,本書會先詳細講解各種知識點的理論,然后再通過示例演示Kotlin各理論的用法,將知識點融合在示例中,符合讀者的認知、學習規律。
另外,整本書的知識具有和《瘋狂Java講義》大致相同的脈絡,所以《瘋狂Java講義》的讀者會很容易上手。
2.講解深入本質
Kotlin是JVM語言,所以其很多東西其實是受到Java的影響的。書中會對一些看似奇怪的語法從字節碼文件層次進行剖析,讓讀者更好地理解Kotlin與Java的對應關系。
比如,主構造器和次構造器到底是什么?Java構造器并不區分主次,為什么Kotlin搞出這兩個東西?主、次構造器為何要委托父類構造器?委托父類構造器時為什么存在區別?主、次構造器生成字節碼之后到底對應Java的哪個部分?這些知識在本書7.5節有深入講解。
再比如,Java本身不支持擴展,那么Kotlin的擴展是如何在JVM上運行的?難道Kotlin改造了JVM嗎?Java本身不支持擴展,那么Java是否可以調用Kotlin擴展的成員?這些問題需要從字節碼層次進行剖析,本書在8.1節有深入講解。
還有,Java泛型的上限、下限的本質是什么?Kotlin泛型的聲明處型變和使用處型變的本質是什么?與Java的對應關系是怎樣的?Java本身并不支持聲明處型變,那為何JVM能支持Kotlin的聲明處型變?這些問題可以在本書第11章中找到答案。
3.知識內容更全面
本書內容超過Kotlin官方文檔本身所覆蓋的知識,比如介紹反射的章節就超過了Kotlin官方文檔內容。本書反射部分不僅更詳細地介紹如何獲得類、函數、屬性的引用,而且真正從API級別介紹KClass、KCallable、KFunction、KProperty,KProperty0、KProperty1、KProperty2的用法,以及它們的內在關聯,并實實在在地教讀者掌握如何用Kotlin反射動態創建對象、動態調用方法。
本書寫給誰看
本書為所有打算深入掌握Kotlin編程的讀者而編寫,尤其適合從Java轉Kotlin的學習者和開發者閱讀,也適合作為大學教育、培訓機構的Kotlin教材。
李剛,十余年軟件開發從業經驗,瘋狂軟件教育中心教學總監。瘋狂Java實訓營創始人,瘋狂Java體系原創圖書作者。廣東技術師范學院計算機科學系兼職副教授,CSDN特邀講師。培訓的學生已在騰訊、阿里、華為、IBM、網易、唯品會、電信盈科等名企就職。國內知名高端IT技術圖書作家,已出版《瘋狂Java講義》《瘋狂Android講義》《輕量級Java
EE企業應用實戰》《瘋狂前端開發講義》《瘋狂HTML5/CSS3/JavaScript講義》《瘋狂iOS講義(基礎篇)(提高篇)》《瘋狂XML講義》《經典JavaEE企業應用實戰》《Struts
2.x權威指南》等著作。其中瘋狂Java體系圖書均已沉淀多年,贏得極高的市場認同,多次重印,多部著作印刷數量超過10萬冊,并被多所985211院校選作教材,部分圖書已被翻譯成繁體中文版,授權到中國臺灣地區。
第1章 Kotlin語言與開發環境1
1.1 Kotlin語言簡介2
1.1.1 服務端的Kotlin2
1.1.2 使用Kotlin開發Android應用2
1.1.3 Kotlin用于JavaScript3
1.2 使用命令行編譯、運行Kotlin3
1.2.1 下載和安裝Kotlin的SDK3
1.2.2 第一個Kotlin程序4
1.2.3 編譯、運行Kotlin程序5
1.3 使用IntelliJ IDEA編譯、運行Kotlin6
1.4 使用Eclipse編譯、運行Kotlin8
1.5 本章小結10
第2章 Kotlin的基礎類型11
2.1 注釋12
2.1.1 單行注釋和多行注釋12
2.1.2 文檔注釋12
2.2 變量14
2.2.1 分隔符15
2.2.2 標識符規則16
2.2.3 Kotlin的關鍵字17
2.2.4 聲明變量19
2.3 整型21
2.4 浮點型23
2.5 字符型24
2.6 數值型之間的類型轉換25
2.6.1 整型之間的轉換25
2.6.2 浮點型與整型之間的轉換28
2.6.3 表達式類型的自動提升28
2.7 Boolean類型30
2.8 null安全31
2.8.1 非空類型和可空類型31
2.8.2 先判斷后使用32
2.8.3 安全調用32
2.8.4 Elvis運算33
2.8.5 強制調用34
2.9 字符串34
2.9.1 字符串類型34
2.9.2 字符串模板35
2.9.3 Kotlin字符串的方法36
2.10 類型別名37
2.11 本章小結38
第3章 運算符和表達式39
3.1 與Java相同的運算符40
3.1.1 單目前綴運算符40
3.1.2 自加和自減運算符41
3.1.3 雙目算術運算符41
3.1.4 in和!in運算符42
3.1.5 索引訪問運算符43
3.1.6 調用運算符43
3.1.7 廣義賦值運算符44
3.1.8 相等與不等運算符44
3.1.9 比較運算符45
3.2 位運算符46
3.3 區間運算符48
3.3.1 閉區間運算符48
3.3.2 半開區間運算符49
3.3.3 反向區間49
3.3.4 區間步長49
3.4 運算符重載50
3.4.1 重載單目前綴運算符50
3.4.2 重載自加和自減運算符51
3.4.3 重載雙目算術運算符51
3.5 本章小結52
第4章 流程控制53
4.1 順序結構54
4.2 分支結構54
4.2.1 if分支54
4.2.2 if表達式58
4.2.3 when分支語句58
4.2.4 when表達式61
4.2.5 when分支處理范圍62
4.2.6 when分支處理類型62
4.2.7 when條件分支63
4.3 循環結構63
4.3.1 while循環64
4.3.2 do while循環65
4.3.3 for-in循環66
4.3.4 嵌套循環66
4.4 控制循環結構68
4.4.1 使用break結束循環68
4.4.2 使用continue忽略本次循環的
剩下語句69
4.4.3 使用return結束方法70
4.5 本章小結71
第5章 數組和集合72
5.1 數組73
5.1.1 創建數組73
5.1.2 使用數組75
5.1.3 使用for-in循環遍歷數組76
5.1.4 使用數組索引76
5.1.5 數組的常用方法77
5.1.6 多維數組80
5.1.7 數組的應用舉例82
5.2 Kotlin集合概述85
5.3 Set集合88
5.3.1 聲明和創建Set集合88
5.3.2 使用Set的方法90
5.3.3 遍歷Set91
5.3.4 可變的Set92
5.4 List集合93
5.4.1 聲明和創建List集合93
5.4.2 使用List的方法94
5.4.3 可變的List95
5.5 Map集合95
5.5.1 聲明和創建Map集合95
5.5.2 使用Map的方法97
5.5.3 遍歷Map98
5.5.4 可變的Map98
5.6 本章小結99
第6章 函數和Lambda表達式100
6.1 函數入門101
6.1.1 定義和調用函數101
6.1.2 函數返回值和Unit102
6.1.3 遞歸函數103
6.1.4 單表達式函數104
6.2 函數的形參105
6.2.1 命名參數105
6.2.2 形參默認值106
6.2.3 尾遞歸函數108
6.2.4 個數可變的形參109
6.3 函數重載110
6.4 局部函數111
6.5 高階函數112
6.5.1 使用函數類型112
6.5.2 使用函數類型作為形參類型113
6.5.3 使用函數類型作為返回值類型114
6.6 局部函數與Lambda表達式115
6.6.1 回顧局部函數116
6.6.2 使用Lambda表達式代替局部函數116
6.6.3 Lambda表達式的脫離117
6.7 Lambda表達式117
6.7.1 調用Lambda表達式118
6.7.2 利用上下文推斷類型118
6.7.3 省略形參名119
6.7.4 調用Lambda表達式的約定120
6.7.5 個數可變的參數和Lambda參數120
6.8 匿名函數121
6.8.1 匿名函數的用法121
6.8.2 匿名函數和Lambda表達式
的return122
6.9 捕獲上下文中的變量和常量123
6.10 內聯函數125
6.10.1 內聯函數的使用125
6.10.2 部分禁止內聯126
6.10.3 非局部返回127
6.11 本章小結128
第7章 面向對象(上)129
7.1 類和對象130
7.1.1 定義類130
7.1.2 對象的產生和使用132
7.1.3 對象的this引用133
7.2 方法詳解136
7.2.1 方法與函數的關系136
7.2.2 中綴表示法137
7.2.3 componentN方法與解構138
7.2.4 數據類和返回多個值的函數140
7.2.5 在Lambda表達式中解構141
7.3 屬性和字段142
7.3.1 讀寫屬性和只讀屬性142
7.3.2 自定義getter和setter144
7.3.3 幕后字段147
7.3.4 幕后屬性148
7.3.5 延遲初始化屬性149
7.3.6 內聯屬性150
7.4 隱藏和封裝151
7.4.1 包和導包151
7.4.2 Kotlin的默認導入153
7.4.3 使用訪問控制符153
7.5 深入構造器155
7.5.1 主構造器和初始化塊156
7.5.2 次構造器和構造器重載158
7.5.3 主構造器聲明屬性161
7.6 類的繼承161
7.6.1 繼承的語法161
7.6.2 重寫父類的方法164
7.6.3 重寫父類的屬性166
7.6.4 super限定167
7.6.5 強制重寫168
7.7 多態169
7.7.1 多態性169
7.7.2 使用is檢查類型170
7.7.3 使用as運算符轉型172
7.8 本章小結174
第8章 面向對象(下)175
8.1 擴展176
8.1.1 擴展方法176
8.1.2 擴展的實現機制179
8.1.3 為可空類型擴展方法182
8.1.4 擴展屬性182
8.1.5 以成員方式定義擴展183
8.1.6 帶接收者的匿名函數184
8.1.7 何時使用擴展186
8.2 final和open修飾符187
8.2.1 可執行宏替換的常量187
8.2.2 final屬性188
8.2.3 final方法189
8.2.4 final類190
8.2.5 不可變類190
8.3 抽象類192
8.3.1 抽象成員和抽象類192
8.3.2 抽象類的作用195
8.3.3 密封類196
8.4 接口198
8.4.1 接口的定義198
8.4.2 接口的繼承199
8.4.3 使用接口200
8.4.4 接口和抽象類202
8.5 嵌套類和內部類202
8.5.1 內部類204
8.5.2 嵌套類207
8.5.3 在外部類以外使用內部類209
8.5.4 在外部類以外使用嵌套類209
8.5.5 局部嵌套類210
8.5.6 匿名內部類211
8.6 對象表達式和對象聲明212
8.6.1 對象表達式212
8.6.2 對象聲明和單例模式215
8.6.3 伴生對象和靜態成員217
8.6.4 伴生對象的擴展218
8.7 枚舉類219
8.7.1 枚舉類入門219
8.7.2 枚舉類的屬性、方法和構造器221
8.7.3 實現接口的枚舉類222
8.7.4 包含抽象方法的抽象枚舉類222
8.8 類委托和屬性委托223
8.8.1 類委托224
8.8.2 屬性委托225
8.8.3 延遲屬性227
8.8.4 屬性監聽228
8.8.5 使用Map存儲屬性值230
8.8.6 局部屬性委托231
8.8.7 委托工廠233
8.9 本章小結234
第9章 異常處理236
9.1 異常處理機制237
9.1.1 使用try...catch捕獲異常237
9.1.2 異常類的繼承體系240
9.1.3 訪問異常信息242
9.1.4 異常處理嵌套243
9.1.5 try語句是表達式243
9.2 使用throw拋出異常243
9.2.1 拋出異常243
9.2.2 自定義異常類244
9.2.3 catch和throw同時使用245
9.2.4 異常鏈246
9.2.5 throw語句是表達式247
9.3 異常的跟蹤棧248
9.4 本章小結250
第10章 泛型251
10.1 泛型入門252
10.1.1 定義泛型接口、類252
10.1.2 從泛型類派生子類253
10.2 型變254
10.2.1 泛型型變的需要254
10.2.2 聲明處型變256
10.2.3 使用處型變:類型投影258
10.2.4 星號投影260
10.3 泛型函數261
10.3.1 泛型函數的使用261
10.3.2 具體化類型參數262
10.4 設定類型形參的上限263
10.5 本章小結264
第11章 注解266
11.1 Kotlin注解入門267
11.1.1 定義注解267
11.1.2 注解的屬性和構造器268
11.2 元注解270
11.2.1 使用@Retention270
11.2.2 使用@Target271
11.2.3 使用@MustBeDocumented272
11.2.4 使用@Repeatable標記可重復注解273
11.3 使用注解273
11.3.1 提取注解信息273
11.3.2 使用注解的示例274
11.4 Java注解與Kotlin的兼容性279
11.4.1 指定注解的作用目標279
11.4.2 使用Java注解281
11.5 本章小結282
第12章 Kotlin與Java互相調用283
12.1 Kotlin調用Java284
12.1.1 屬性284
12.1.2 void和調用名為關鍵字的成員285
12.1.3 Kotlin的已映射類型286
12.1.4 Kotlin對Java泛型的轉換287
12.1.5 對Java數組的處理287
12.1.6 調用參數個數可變的方法288
12.1.7 checked異常289
12.1.8 Object的處理289
12.1.9 訪問靜態成員290
12.1.10 SAM轉換290
12.1.11 在Kotlin中使用JNI291
12.2 Java調用Kotlin291
12.2.1 屬性291
12.2.2 包級函數292
12.2.3 實例變量294
12.2.4 類變量294
12.2.5 類方法296
12.2.6 訪問控制符的對應關系297
12.2.7 獲取KClass298
12.2.8 使用@JvmName解決簽名沖突298
12.2.9 生成重載299
12.2.10 checked異常300
12.2.11 泛型的型變300
12.3 Kotlin反射302
12.3.1 類引用302
12.3.2 從KClass獲取類信息303
12.3.3 創建對象306
12.3.4 構造器引用306
12.3.5 調用方法307
12.3.6 函數引用308
12.3.7 訪問屬性值309
12.3.8 屬性引用311
12.3.9 綁定的方法與屬性引用313
12.4 本章小結313