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"//静态常量
      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阅读 199,902评论 5 468
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 84,037评论 2 377
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,978评论 0 332
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,867评论 1 272
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,763评论 5 360
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,104评论 1 277
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,565评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,236评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,379评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,313评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,363评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,034评论 3 315
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,637评论 3 303
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,719评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,952评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,371评论 2 346
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,948评论 2 341

推荐阅读更多精彩内容

  • 项目未来可能需要使用kotlin开发,所以特此记录一下学习笔记,仅供参考,方便后期查询。已同步到GitHub上:K...
    下位子阅读 2,487评论 7 17
  • 第一章 定义和目的 kotlin的主要特征 目标平台:服务器端,Android及任何Java运行的地方 静态类型 ...
    WangGavin阅读 605评论 0 1
  • 首发于公众号: DSGtalk1989 5.Kotlin 类和对象 构造器kotlin中一个类只能有一个主构造器和...
    super_shanks阅读 1,016评论 0 1
  • Kotlin 学习笔记(一) Kotlin初识 这是一个Kotlin系列的教程,目的是为了使自己记忆和理解的更加深...
    真的有照片阅读 1,191评论 1 6
  • 久违的晴天,家长会。 家长大会开好到教室时,离放学已经没多少时间了。班主任说已经安排了三个家长分享经验。 放学铃声...
    飘雪儿5阅读 7,458评论 16 22