Kotlin进阶学习笔记

2021-01-26  本文已影响0人  志威梦

Kotlin进阶学习笔记

从源码分析学习Kotlin,知其然、知其所以然。

通用基础语法学习Kotlin官网快速语法学习笔记

1. Why Kotlin 之官方说辞
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

以上为Kotlin进阶学习中着意知识点;接下来会分析Kotlin的类型推断原理、泛型、反射以及其他高阶特性。

上一篇下一篇

猜你喜欢

热点阅读