Kotlin進階學習筆記

Kotlin進階學習筆記

從源碼分析學習Kotlin,知其然、知其所以然。

通用基礎語法學習Kotlin官網快速語法學習筆記

1. Why Kotlin 之官方說辭
  • 簡潔Concise:data classlambda快速單例類object

  • 安全Safe:Nullable類型區分,自動推斷

    //區分nullable
      var str:String//不同于String?
      str=null//編譯則報錯,因為String類型非空,任何可空類型需要?符號,比如String?
      //避免NPE
      val name:String?=null//name是可空的
      println(name.length())//編譯報錯,原因name可能為null,會引起name.length()報空指針異常
      //自動類型推斷
      val str:Any//外部參數
      if(str is String){
          //此處在str is String作用域內,就不需要強轉類型了
          str.length()
      }
    
  • 互操作性Interoperable

    官宣與Java的現有庫可以100%的兼容使用

2. 源碼分析簡潔/安全/互通性
  1. 語法簡潔

    類型定義,函數聲明,POJO創建,labmda的隨處可見,快速單例類等都是kotlin語法簡潔的有力證明。

    • POJO的對比

      public class Student{
        private String name;
        private int age;
        private String desc;
        
        public void setName(String name){
          this.name = name;
        }
        //省略...
      }
      
      //kotlin中的data class專用于POJO的創建生成,并內部實現了getter/setter,toString,equals,hashCode等必要函數
      data class Student(val name:String,var age:Int,val desc:String)
      

      注意??:可通過AS的Tools-->kotlin-->show kotlin Bytecode在IDE中顯示當前kotlin文件對應的字節碼,點擊Decompile即可生成對應的java文件,從而對比kotlin于java的異同。

    • 單例類的快速創建

      object Tools{
        fun abc(){
          //...
        }
      }
      
      //對應java文件大致如此,之所以有final,因為在kotlin中默認定義的類、函數都是final不可繼承的。
      public final class Tools{
        
        @NotNull
        public static final Tools INSTANCE;
        
        public final void abc(){
          //....
        }
        static{
          Tools var0 = new Tools();
          INSTANCE = var0;
        }
      }
      

      通過AS操作對比生成的java文件,我們可以看得出,如上簡單的object單例類,對應于java中就是static京臺單例類的寫法。

  2. 安全性

    • Kotlin中最大的一點在于很好的避免大多數的空指針異常(NPE)的發生,原因在于其從語法層級就區分了 nullablenotnull的類型,如字符串類型String則在kotlin中就表示聲明該類型不能賦值null,若要用null的賦值,則必須是String?方可。同理其他類型如是。
    • 在與Java互通時候,就需要Java端的字段與函數標記nullable或notnull注解才能讓kotlin正確的接收類型。

操作示例圖

show kotlin bytecode
  1. 互通

    雖然號稱和Java的100%兼容互通,在項目開發中仍然要有一些細節點注意

    • Kotlin調用Java

      1. getter(無參)setter(單個單數)java方法可映射為kotlin中對象屬性。Booleangetter理解為isXXX

        public class AA{
            private String name;
            private boolean adult;
            
            public void setName(String name){
                this.name = name;
            }
            public String getName(){
                return name;
            }
            public void setAdult(boolean adult){
                this.adult = adult;
            }
            public boolean isAdult(){
                return adult;
            }
        }
        
        fun test(){
            val aa = AA()
            //kotlin中調用java,對應getter和setter可映射為kotlin中的屬性
            aa.name = "Julia"
            aa.isAdult = true
        }
        
      2. 特殊字符,如isobjectis等在java中無所謂,但是在kotlin中是關鍵字,調用時候需要轉義

        //如java中定義一個函數名public void is(String name){}
        //kotlin調用的時候,is要轉義
        aa.`is`("name")
        
      3. 空安全,java中任何引用都可能null,所以kotlin調用java就比較尷尬。

        1. 編譯器可能無法判斷類型可空與否。在接收java類型時,可根據情況最好注解為可null

        2. 參照java中注解@Nullable@NotNull,則在kotlin中調用可明確類型空否。

          public void setName(@NotNull String name){
              //....
          }
          @Nullable
          public String getName(){
              return name;
          }
          //在kotlin調用如上函數,就比較明晰,如果沒有注解的話,就要靈活判斷
          
      4. Java中泛型在Kotlin中的使用,轉換

        1. Foo<? extends Bar>——>Foo<out Bar!>!
        2. Foo<? super Bar> ——> Foo<in Bar!>!
        3. Java中原始類型如List轉化為List<*>!,即List<out Any?>!
        4. 同樣Kotlin的泛型也存在類型擦除問題。泛型詳細講解,之后單獨文章分析
      5. Java中數組是可型變的,Kotlin中數組不可型變。Kotlin中基礎類型隱藏了拆裝箱的細節,對應于原生java的數組提供了特殊類來映射。IntArrayDoubleArray等,但這些都不是數組,對應會編譯為Java的原生數組。

        //Java數組方法
        public class JavaArrayTest{
            public void removeIndices(int[] indices){
                //...
            }
        }
        //kotlin中調用java的數組參數的方法
        fun testJavaArray(){
            val javaObj = JavaArrayTest()
            val arr = intArrayOf(1,2,2,3)//生成kotlin語法的數組
            javaObj.removeIndices(arr)//調用java的方法,傳入數組參數
            
            //更新賦值,遍歷,均不會引入額外開銷
            arr[2] = arr[1]*3//將2號位的值更新為1號值得3倍,這里也不會有get/set的調用
           for(x in arr){//并不會創建迭代器
               print(x)
           }
           for(i in arr.indices){//也不會有迭代器創建,不會有額外開銷,in的校驗也不會有額外開銷。
               arr[i]+=3
           }
        }
        

        因為kolint的語法特定類,在編譯為JVM的字節碼時候,會化為原生的形式。

        Java的數組可型變與Kotlin的數組不可型變,對比圖

arr

java arr
  1. Java可變參數,Kotlin中使用*符號展開對應數組,不可傳null
        //Java中可變參數使用...表示
        public void removeIndices(int... indices){
            //...
        }
        //kotlin中調用就需要是對應可展開的數組類型
        val aar = intArrayOf(1,2,2,3)
        removeIndices(*arr)
  1. Kotlin中無法使用中綴語法調用Java方法

  2. Kotlin中可能異常的函數,并不會要求你一定try...catch,這就有點尷尬,你嗲用Java或者kotlin的其他可能異常的函數時候,就要自己注意catch

  3. Java類的靜態成員會在Kotlin中表示為伴生對象companion object

  4. Java反射與Kotlin反射類似,后續文章單獨分析

  5. SAM(simple abstract method conversions)轉換。

  6. Kotlin調用JNI,類似于Java,需要在Kotlin中聲明一個函數,在C/C++中有實現的,并使用external修飾

        external fun aaa(a:Int):Double//這個函數,在Kotlin中聲明,需要在C/C++中實現。
        //也可以是屬性的形式,這樣就是生成兩個external的函數,setter/getter
        var mName:String
           external get
           external set
  • Java中調用Kotlin

    1. Kotlin中頂級函數和字段,在Java中調用

      //文件名叫做 test.kt
      package org.zhiwei
      
      class ABC(){}
      //top level 的函數和字段
      fun getName(){
          //...
      }
      const val bbbb = "bbbbb"http://靜態常量
      var cccccc= ""
      val dddddd = ""
      

      通過編譯,會生成org.zhiwei.testKt類,成為內部方法和屬性。

      //java中調用則
      org.zhiwei.testKt.getName();//函數
      org.zhiwei.testKt.bbbb;//靜態常量  
      org.zhiwei.testKt.setCccccc("");//可變量
      

      默認生成fileNameKt,可通過@JvmName指定生成的類名/函數名

      @file:JvmName("TestTools")//則在java中調用就用TestTools.來調用即可。
      

      注:不同的kt文件中toplevel可以指定生成相同的Java類,需要添加@file:JvmMultifileClass注解

      //oldUtils.kt
      @file:JvmName("Tools")
      @file:JvmMultifileClass
      
      package org.zhiwei
      
      fun getTime(){
          //...
      }
      //newUtils.kt
      @file:JvmName("Tools")
      @file:JvmMultifileClass
      
      package org.zhiwei
      
      fun getDate(){
          //...
      }
      //如上兩個kt文件中不同的top level的函數定義,都指定生成java文件Tools類,
      
      //java中調用,就是如下
      Tools.getTime();
      Tools.getDate();
      
    2. Kotlin中非私有/非open/override/非const/無默認值/非被委托的屬性,通過@JvmField修飾,可在Java中調用。

      //kotlin
      class User(id:String){
          @JvmField val ID = id
      }
      //java中 
      public String getId(User user){
          return user.ID;
      }
      
    3. Kotlin中靜態字段通常會是私有的。可通過@JvmField/lateinit/const來修飾,使得Java中公開調用到。

      //kotlin
      class User(){
          companion object{
              const val SEX = '男'
              @JvmField
              val name = "張三"
              lateinit var mobile:String
          }
      }
      //java中,注意,不需要UserKt.的形式
      User.SEX;
      User.name;
      User.mobile;
      
    4. kotlin中靜態方法對應于Java中,@JvmStatic注解適用于字段和函數(jdk1.8/kotlin 1.3)

      //top level中的靜態函數都是java對應的。而在具體的類中,可以寫在object或者伴生對象中
      class CCC{
          companion object{
              //在kotlin中屬于靜態函數的調用方式,但是java調用就需要伴生對象形式
              fun callInKotlinStatic(){}
              //支持如上方式,但同時在java中也是靜態調用方式
              @JvmStatic fun callInJavaStatic(){}
          }
      }
      //java中
      public void test(){
          CCC.callInJavaStatic();
          CCC.Companion.callInJavaStatic();
          CCC.Companion.callInKotlinStatic();//只有這一個,沒有直接CCC.callInKotlinStatic()
          
      }
      
    5. Kotlin中接口的函數定義,可以有默認實現(jdk1.8+)

      interface IUser{
          fun run(){
              //...默認實現
          }
      }
      //java實現接口的時候,可以不復寫run函數
      
    6. 權限符號publicprivateinternalprotectedJava中異同

      1. private、public權限一致;private在kt文件級別,則等同于包內可見。
      2. Java中可以訪問包內的其他protected的類,kotlin不行
      3. internal的屬性字段,對應java的public,而internal 的類的成員,與java中作用關系無對應。
    7. KClass調用可用getKotlinClass(XXX.class)

    8. Jvm的簽名沖突處理,@JvmName處理

      //kotlin中定義兩個同名函數
      fun List<String>.filterN():List<String>
      fun List<Int>.filterN():List<Int>
      //屬性的setter和getter也可以單獨注解
      val x:Int
      @JvmName("getX_prop")
      get() = 888
      //或者
      @get:JvmName("x")
      @set:JvmName("changeX")
      var x:Int = 33
      
    9. @JvmOverloads函數重載,用于將kotlin中存在默認參數的函數,提供出多種重載函數給Java調用。可用于構造函數和靜態函數,不能修飾抽象函數和接口的方法。

      //這個函數存在java中就會有依次的集中重載組合函數
      @JvmOverloads
      fun haha(name:String,age:Int=18,sex:Int=1,address:String="beijing")
      
    10. 異常,kotiln不檢查異常,所以想要讓調用方知道會異常就添加@Throws

      @Throws(IOException::class)
      fun write2File(){
          //...
          throw IOException()
      }
      
    11. Java中的類型參數可能接收null,并且kotlin不知道,比較尷尬。

    12. Nothing類型,在Java中沒有對應。Nothing不能為null

以上為Kotlin進階學習中著意知識點;接下來會分析Kotlin的類型推斷原理、泛型、反射以及其他高階特性。

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 230,563評論 6 544
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 99,694評論 3 429
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 178,672評論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,965評論 1 318
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 72,690評論 6 413
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 56,019評論 1 329
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 44,013評論 3 449
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 43,188評論 0 290
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,718評論 1 336
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 41,438評論 3 360
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,667評論 1 374
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 39,149評論 5 365
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,845評論 3 351
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,252評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,590評論 1 295
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 52,384評論 3 400
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,635評論 2 380

推薦閱讀更多精彩內容

  • 項目未來可能需要使用kotlin開發,所以特此記錄一下學習筆記,僅供參考,方便后期查詢。已同步到GitHub上:K...
    下位子閱讀 2,511評論 7 17
  • 第一章 定義和目的 kotlin的主要特征 目標平臺:服務器端,Android及任何Java運行的地方 靜態類型 ...
    WangGavin閱讀 610評論 0 1
  • 首發于公眾號: DSGtalk1989 5.Kotlin 類和對象 構造器kotlin中一個類只能有一個主構造器和...
    super_shanks閱讀 1,069評論 0 1
  • Kotlin 學習筆記(一) Kotlin初識 這是一個Kotlin系列的教程,目的是為了使自己記憶和理解的更加深...
    真的有照片閱讀 1,214評論 1 6
  • 久違的晴天,家長會。 家長大會開好到教室時,離放學已經沒多少時間了。班主任說已經安排了三個家長分享經驗。 放學鈴聲...
    飄雪兒5閱讀 7,550評論 16 22