Android技术知识Android开发经验谈Android开发

Kotlin机制总结

2021-03-24  本文已影响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")
    }
}

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

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

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

举例如下,这些函数用法与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 中调用静态属性和静态方法;
伴生对象可以扩展属性和扩展方法。

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

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

上一篇下一篇

猜你喜欢

热点阅读