Kotlin机制总结

作者: 奔跑吧李博 | 来源:发表于2021-03-24 23:56 被阅读0次
    什么是kotlin?

    kotlin是静态类型的编程语言,运行于jvm之上。如果在编译时知道变量的类型,则语言是静态类型的,在运行时知道变量类型,则语言是动态类型。

    什么是extension(扩展)函数

    Kotlin 可以对一个类的属性和方法进行扩展,对被扩展的类代码本身不会造成任何影响。
    扩展函数可以为已经存在的类添加新的方法,并且不会修改原来的类。

    class MainActivity : AppCompatActivity() {
        override fun onCreate(savedInstanceState: Bundle?) {
            super.onCreate(savedInstanceState)
            setContentView(R.layout.activity_main)
    
           User("libo", 10).login()
        }
    
        fun User.login() {
            Log.i("TAG","去登录")
        }
    }
    
    data class User(var name: String, var age: Int)
    
    在kotlin中有多少种构造函数

    kotlin将构造函数分为了两种:主构造函数和次构造函数。

    //主构造方法如下,跟在类名后面
    class Person constructor(name:String){
        
    }
    //无参主构造方法
    class Person constructor(){
        
    }
    //当主构造方法没有任何注解或者可见性修饰符时,可以省略,写成下面这样
    class Person {
        
    }
    
    class Person {
        
        /**
         * 无参次构造方法
         */
        constructor(){
    
        }
        /**
         * 有参次构造方法
         */
        constructor(name:String){
    
        }
    }
    

    主构造函数没有函数体,如果我们想在主构造函数中写一些逻辑,怎么办呢,kotlin给我们提供一个init结构体,所有构造函数中的逻辑都可以写在里面:

    class Person(val name: String, val age: Int) : Person() {
        init {
            println("name is $name")
            println("age is $age")
        }
    }
    
    • lateinit和by lazy的区别

    Kotlin 基于 Java 的空指针提出了一个空安全的概念,即每个属性默认不可为null。 在某个类中,如果某些成员变量没办法在一开始就初始化,并且又不想使用可空类型(也就是带?的类型)。那么,可以使用lateinit或者by lazy来修饰它。

    1.lateinit 只能用于修饰变量 var,不能用于可空的属性和 Java 的基本类型。
    2.lateinit 可以在任何位置初始化并且可以初始化多次。
    3.lazy 只能用于修饰常量 val,并且 lazy 是线程安全的。
    4.lazy 在第一次被调用时就被初始化,以后调用该属性会返回之前的结果。

    • let, apply, run, with的区别
    • 高阶函数

    如果一个函数接收另一个函数作为参数,或者返回类型是一个函数,那么这个函数我们就称之为高阶函数。

    举例如下,这些函数用法与Rxjava同名函数类似

            //forEach,用于遍历集合
            val arr = intArrayOf(1, 2, 4, 6)
            arr.forEach {
                println(it)
            }
    
             //map 返回一个每一个元素根据给定的函数转换所组成的List
            val arr = intArrayOf(1, 2, 4, 6)
            val newArr = arr.map { (it * 2).toString()  }
            println(newArr)
    
            //flatMap  遍历所有的元素 ,为每一个创建一个集合 ,最后把所有的集合放在一个集合中
            val arr = intArrayOf(1, 2, 4, 6)
            val arr2 = intArrayOf(10, 39, 39, 18, 88)
            var arr3 = intArrayOf(100, 200, 383, 198)
            arrayListOf(arr, arr2, arr3).flatMap { iterator ->
                iterator.map {
                    println(it.toString())
                }
            }
            
            //filter,用于过滤数据
            val arr = intArrayOf(1, 2, 7, 6, 10, 39, 39, 18, 88)
            arr.filter {
                //这里是通过条件
                it % 2 == 0
            }
    
            //takeWhile,带满足条件的过滤
            //它的实现和filter不同地方在filter总是会遍历当前IntArray的所有元素,而takeWhile在第一次发现元素不满足的时候就不再遍历
            val arr = intArrayOf(1, 2, 4, 6, 8, 9, 10, 12, 14)
            arr.takeWhile {
                it % 2 == 0
            }
    
            //take/takeLast
            val arr = intArrayOf(1, 2, 4, 6, 8, 9, 10, 12, 14)
            var list = arr.take(5)  //取前5个
            var list2 = arr.takeLast(3)  //取后3个
    
    • 伴生对象的总结

    类似于 Java 中使用类访问静态成员的语法。因为 Kotlin 取消了 static 关键字,所以 Kotlin 引入伴生对象来弥补没有静态成员的不足。可见,伴生对象的主要作用就是为其所在的外部类模拟静态成员。

    每个类可以最多有一个半生对象;
    使用 const 关键字修饰常量,类似于 Java 中的 static final修饰。
    可以使用 @JvmField 和 @JvmStatic 类似于 Java 中调用静态属性和静态方法;
    伴生对象可以扩展属性和扩展方法。

    • init代码块和构造方法以及伴生对象中代码的调用时机

    创建Person类,创建person对象打印方法调用时机:

    class Person {
        private var name: String = "jack"
        constructor() {
            println("constructor 方法调用")
        }
        init {
            println("init 方法调用")
        }
        companion object {
            init {
                println("companion init 1")
            }
        }
    }
    

    从Tools-->kotlin-->show Kotlin Bytecode,将Person类反编译成java类得到:


    伴生对象转为了静态代码块,init代码块插入到了构造方法的开头处。静态代码块在编译期运行,然后依次运行构造方法的代码。打印的结构为:

    结论:伴生对象先于init方法,再先于构造方法。首先伴生对象中的代码是在类加载时就会执行。init代码块中的方法会按顺序放在主构造函数中,主构造函数中原来的代码会在后面执行。

    • const和val有什么区别?

    所述const关键字被用于声明那些不可变在本质即,这些属性是只读属性的属性。
    但是,这些属性的值必须仅在编译时已知,这const就是也称为编译时常量的原因。相当于java中的static final修饰。该val关键字还用于只读属性。但是const和之间的主要区别在于val,val属性也可以在运行时进行初始化,即不可变变量。

    • Kotlin data类机制

    创建DataBean类:

    class DataBean(var uId: Int, val phoneNum: String, val address: String)
    

    转成java类,知道为什么Kotlin开发强大了吧。

    public final class DataBean {
       private int uId;
       @NotNull
       private final String phoneNum;
       @NotNull
       private final String address;
    
       public final int getUId() {
          return this.uId;
       }
    
       public final void setUId(int var1) {
          this.uId = var1;
       }
    
       @NotNull
       public final String getPhoneNum() {
          return this.phoneNum;
       }
    
       @NotNull
       public final String getAddress() {
          return this.address;
       }
    
       public DataBean(int uId, @NotNull String phoneNum, @NotNull String address) {
          Intrinsics.checkNotNullParameter(phoneNum, "phoneNum");
          Intrinsics.checkNotNullParameter(address, "address");
          super();
          this.uId = uId;
          this.phoneNum = phoneNum;
          this.address = address;
       }
    }
    

    反编译成java代码后自动生成了变量的get、set方法,equals方法,copy方法,hashCode()方法。如果这些函数中的任何一个在类体中显式定义或继承自其基类,则不会自动生成该函数。如果变量是val修饰,只会生成get方法。

    • 什么是Range操作符?

    Range是Kotlin相对Java新增的一种表达式,它表示的是值的范围,类似于数学中的区间。
    Range的表达式是像这样子的:1..20,其中..是运算符,它表示一个闭区间[1, 20]。

    相关文章

      网友评论

        本文标题:Kotlin机制总结

        本文链接:https://www.haomeiwen.com/subject/reqchltx.html