• Android Kotlin 高阶详解


    前言

    本文主要讲述kotlin高阶相关的内容,如果对kotlin基础还不了解的,

    可以参考文章Android Kotlin 基础详解_袁震的博客-CSDN博客

    1,与Java的相互调用

    1.1在kotlin中调用java代码

    大多数的java代码都可以直接在kotlin中调用,没有问题,但是有一些代码是不能直接调用的,这里需要注意一下

    1.1.1 含有关键字的方法

    某些kotlin关键字在java中是合法的标识符,in, object,is等等,如果java类中使用kotlin关键字作为方法名,我们仍然可以调用这个方法,只要使用反引号`对方法名转义即可:

    在java中:

    1. public class JavaTest {
    2. public void in(){
    3. System.out.println("输出in");
    4. }
    5. }

    在kotlin中调用:

    1. var javaTest =JavaTest()
    2. javaTest.`in`()

    1.1.2null值安全性与平台数据类型

    1. Java 中的所有引用都可以为 null 值, 因此对于来自 Java 的对象,
    2. Kotlin 的严格的 null 值安全性要求就变得毫无意义了.
    3. Java 中定义的类型在 Kotlin 中会被特别处理,
    4. 被称为 平台数据类型(platform type). 对于这些类型,
    5. Null 值检查会被放松, 因此对它们来说, 只提供与 Java 中
    6. 相同的 null 值安全保证

     比如:

    1. val list =ArrayList()//非null值 因为是构造器方法的返回结果
    2. list.add("yuanzhen")
    3. val size =list.size //非null值 因为是基本数据类型int
    4. //报异常 Index 1 out of bounds for length 1
    5. val item =list.get(1)//类型自动推断结果为平台类型,通常的java对象
    6. item.substring(2)//

    1.1.3@Nullable 和@NotNull

    带有@Nullable 和@NotNull的注解的Java类型在kotlin中不会被当作平台数据类型,而会被识别为可为null的,或非null的kotlin类型

    也可以对泛型的类型参数添加注解, 标记它是否可以为 null. 比如, 我们先来看看在 Java 中如何添加这些注解:
    1. @NotNull
    2. Set<@NotNull String> toSet(@NotNull Collection<@NotNull String> elements) {
    3. ...
    4. }

    在kotlin中如下:

    fun toSet(elements: (Mutable)Collection<String>) : (Mutable)Set { ... }
    请注意在类型参数 String 上的 @NotNull 注解. 如果没有这些注解, 我们得到的类型参数就只能是平台数据类型:
    fun toSet(elements: (Mutable)Collection<String!>) : (Mutable)Set { ... }
    1. (Mutable)Collection! 代表 “元素类型为 T 的Java 集合,
    2. 内容可能可变, 也可能不可变,
    3. 值可能允许为 null, 也可能不允许为null”,
    4. Array<(out) T>! 代表 “元素类型为 T (或 T 的子类型)的 Java 数组,
    5. 值可能允许为 null, 也可能不允许为 null

     1.1.4 数据类型映射

    kotlin会对某些java类型进行特殊处理,这些类型会被从java中原封不动的装载进来,但被映射为对应的kotlin类型。映射过程只会在编译时发生,运行时的数据表达不会发生变化。映射关系如下:

    有些内建类虽然不是基本类型, 也会被映射为对应的 Kotlin 类型:

    Java 中的装箱的基本类型(boxed primitive type), 会被映射为 Kotlin 的可为 null 类型:

    注意, 装箱的基本类型用作类型参数时, 会被映射为平台类型: 比如, List 在 Kotlin 中会变为 List .
    集合类型在 Kotlin 中可能是只读的, 也可能是内容可变的, 因此 Java 的集合会被映射为以下类型(下表中所有的 Kotlin 类型都属于
    kotlin.collections 包):
    Java 数据的映射如下:

    1.1.5泛型

    Kotlin 的泛型 与 Java 的泛型略有差异 . 将 Java 类型导入 Kotlin 时, 我们进行以下变换:
    Java 的通配符会被变换为 Kotlin 的类型投射,
    Foo 变换为 Foo! ,
    Foo 变换为 Foo! ;
    Java 的原生类型(raw type) 转换为 Kotlin 的星号投射(star projection),
    List 变换为 List<*>! , 也就是 List! .
    与 Java 一样, Kotlin 的泛型信息在运行时不会保留, 也就是说, 创建对象时传递给构造器的类型参数信息, 在对象中不会保留下来, 所以,
    ArrayList() 与 ArrayList() 在运行时刻是无法区分的. 这就导致无法进行带有泛型信息的 is 判断. Kotlin 只允许对
    星号投射(star projection)的泛型类型进行 is 判断:
    1. if (a is List<Int>) // 错误: 无法判断它是不是 Int 构成的 List
    2. // 但是
    3. if (a is List<*>) // OK: 这里的判断不保证 List 内容的数据类型

    1.1.6 获得java类

    要在kotlin中,获取java类,有两种写法:

    1. val clazz = javaTest::class.java
    2. val clazz1 = javaTest.javaClass

    1.2 在java中调用kotlin代码

    调用 Kotlin 中的方法时, 有时你可能会需要使用 KClass 类型的参数. Java 的 Class 不会自动转换为 Kotlin 的 KClass , 因此你必须手动
    进行转换, 方法是使用 Class.kotlin 扩展属性, 这个扩展属性对应的方法是:
    kotlin.jvm.JvmClassMappingKt.getKotlinClass(MainView.class)

    java中访问Kotlin文件中的函数,需要使用:文件名Kt.函数名进行访问

    MyClassKt.test();

    在Kotlin中,可以把很多具有相似功能的函数放到同一个kotlin文件中,如果想要以Java中类似静态方法的形式访问Kotlin文件中的函数(不使用文件名Kt进行访问),可以通过使用@file:JvmName("任意名称")注解来达成目标。需要注意的是,@file:JvmName("名称") 一定要放在文件的最开始,要在包声明之前

    1. @file:JvmName("Test")
    2. package com.yuanzhen.kotlinstudy
    3. fun test1(){
    4. println("测试JvmName")
    5. }

    在java中调用:

    Test.test1();


    2.动态代理

    Kotlin原生支持了动态代理语法,通过by关键字实现,省略了Java中要手写代理类实现InvocationHandler 接口, 通过Proxy获取代理类调用方法等一系列步骤。

    1. interface Animal{
    2. fun bark()
    3. }
    4. class Dog : Animal{
    5. override fun bark() {
    6. println("Wang")
    7. }
    8. class Duck : Animal{
    9. override fun bark() {
    10. println("Ga ga")
    11. }
    12. }
    13. class Zoo(animal : Animal) : Animal by animal
    14. fun main(){
    15. Zoo(Dog()).bark()
    16. Zoo(Duck()).bark()
    17. }

    注意:如果在Zoo中重写了代理接口中的方法,则会执行重写方法中的代码,不会再执行代理类中的方法了

    Kotlin的动态代理会在编译以后将动态代理转换为**静态代理**以后来使用,所以Kotlin中的动态代理要比java中的效率高。java动态代理请参考Java 代理模式之静态代理与动态代理_袁震的博客-CSDN博客

    3,密闭类

    kotlin很少使用枚举类,通常使用更强大的密闭类。密闭类使用关键字sealed来定义

    一个密闭类可以有多个子类,但是密闭类必须和其子类都在同一个kt文件中

    密闭类可以有成员变量,但必须是abstract的

    1. sealed class Fruit{
    2. abstract var name:String
    3. }
    4. class Apple:Fruit(){
    5. override var name: String = "Apple not good"
    6. }
    7. class Pear:Fruit(){
    8. override var name: String = "Pear good"
    9. }
    10. fun echoFruitName(fruit:Fruit){
    11. when(fruit){
    12. is Apple -> println(fruit.name)
    13. is Pear -> println(fruit.name)
    14. }
    15. }
    16. fun main() {
    17. echoFruitName(Pear())
    18. echoFruitName(Apple())
    19. }

    4,泛型

    请参考文章Android泛型详解_袁震的博客-CSDN博客

    5,init代码块

    init代码块会在类每次实例化时都执行一次,执行顺序为 主构造>init代码块>次级构造,因此可以在init代码块中执行一部分主构造中无法执行的逻辑代码。

    1. class People(var name:String){
    2. constructor(name:String, age:Int):this(name){
    3. println("in constructor")
    4. }
    5. init {
    6. name = name + "00"
    7. println("in init block name = $name")
    8. }
    9. }
    10. fun main(){
    11. People("zhangsan", 123)
    12. }

    结果:
    in init block name = zhangsan00
    in constructor 

    6,lateinit 修饰符

    Kotlin中类的属性必须初始化,否则编译器会报错。为了让大家更适应类似Java中的写法,Kotlin提供了一个关键字lateinit,可以告诉编译器稍后我会初始化这个字段。但是需要注意:如果这个属性没有初始化就使用的话,会报空指针异常

    7,扩展函数,扩展属性

    Kotlin中可以给一个类扩展它的成员方法或成员变量,常用于扩展系统内置库、三方SDK等不受控的类

    无论是Kotlin中的类,还是Java中的类,kotlin都可以对他们的成员方法进行扩展

    fun 被扩展方法的类名.扩展方法名(参数列表):返回值 = 实现{ 函数体 }
    1. class TestKtClass{
    2. }
    3. fun TestKtClass.echoMsg(str:String) = println(str)
    4. fun TestKtClass.getStrValue(str1:String, str2:String):Int{
    5. return (str1+str2).length
    6. }
    7. fun main(){
    8. TestKtClass().echoMsg("12345")
    9. println(TestKtClass().getStrValue("12345", "000"))
    10. }

    注意点:

    1.扩展函数时静态的给一个类添加成员方法,不具备运行时多态效应

    2.扩展函数和类内部定义的成员函数重名时,执行的是类的成员函数

    扩展属性和扩展函数类似,

    1. var 类名.属性名称:类型
    2. get(){
    3. }
    4. set(value){
    5. }
    1. var StringBuilder.firstLetter:Char
    2. get(){
    3. return get(0)
    4. }
    5. set(value){
    6. this.setCharAt(0, value)
    7. }
    8. fun main(){
    9. println(StringBuilder("123456").firstLetter)
    10. }

    8,静态对象

    使用关键字object定义的对象是静态对象,此对象类似于静态对象仅能被实例化一次,相当于单例并且线程安全

    object类不能有构造函数 

    1. object TestObj{
    2. fun echoName(){
    3. }
    4. }
    5. fun main(){
    6. TestObj.echoName()
    7. }

    在kotlin中调用object对象的方法,使用类名.方法名调用

    在Java中调用object对象的方法,使用类名.INSTANCE.方法名调用

    TestObj.INSTANCE.echoName();

    9,伴生对象

    伴生对象使用companion object关键字定义,并且仅能在一个类的内部使用,因此才叫伴生对象,伴生对象中的方法和属性都是相当于静态(并不是真正的静态,而是包含在一个静态实例中)的。

    1. class TestCompanionObj{
    2. companion object{
    3. fun echoMsg(){
    4. println("111111111111111111")
    5. }
    6. }
    7. }

    object类似,在kotlin中使用类名.方法名调用, 在Java中使用类名.Companion.方法名调用

    1. //kotlin
    2. TestCompanionObj.echoMsg()
    3. //java
    4. TestCompanionObj.Companion.echoMsg();

    10,幕后字段

    幕后字段用关键字field表示,仅能用在get和set方法中使用。在Kotlin中,field这个字段代表这个属性本身,与class中的this相似。

    需要注意的是:在get和set方法中,一定不要使用属性本身。因为一旦使用属性本身会被再次展开为get和set方法,造成无限递归,最终引发stack over flow。如果要使用属性(无论读或者写),一定使用幕后字段。

    1. class Test{
    2. var name = ""
    3. set(value) {
    4. //错误的示范,在set使用了name属性本身,应该使用field
    5. name = value
    6. }
    7. }
    1. class Test{
    2. var name = ""
    3. private set(value) {
    4. field = value
    5. }
    6. }

    11,常用的集合操作符

    1. **元素操作类**
    2. - contains :判断是否有指定元素
    3. - elementAt:返回对应元素,越界会抛出IndexOutOfBoundsException
    4. - firstOrNull:返回符合条件的第一个元素,没有返回null
    5. - lastOrNull:返回符合提交的最后一个元素,没有返回null
    6. - indexOf:返回指定元素的下标,没有返回-1
    7. - singleOrNull:返回符合条件的单个元素,如果没有符合或超过1个,返回Null
    8. **判断类**
    9. - any:判断集合中是否有满足条件的元素
    10. - all:判断集合中的元素是否都满足条件
    11. - none:判断集合中是否都不满足条件
    12. - count:查询集合中满足条件的个数
    13. - reduce:从第一项累加到最后一项
    14. **过滤类**
    15. - filter:过滤所有满足条件的元素
    16. - filterOrNot:过滤所有不满足条件的元素
    17. - filterNotNull:过滤NULL元素
    18. - take:返回前N个元素
    19. **转换类**
    20. - map:转换成另外一个集合
    21. - mapIndexed:转换成另外一个集合,还可以拿下标
    22. - mapNotNull:执行转换前先过滤掉为NULL的元素
    23. - flatMap:自定义逻辑合并两个集合
    24. - groupBy:按照某个条件分组,返回map
    25. **排序类**
    26. - reversed:反序
    27. - sorted:升序
    28. - sortedBy:自定义排序
    29. - sortedDescending:降序

    12,运算符重载与中缀表达式

    运算符重载要使用关键字operator,重载运算符有一个要求:只能重载Kotlin中定义好的运算符。

    operator 将一个函数标记为重载一个操作符或者实现一个约定。运算符重载就是对已有的运算符赋予他们新的含义。

    Kotlin中的 && 、 || 、 ?: 、 === 、 !== 是不能被重载的

    1. data class Person(var name: String, var age: Int)
    2. operator fun Int.plus(b: Person): Int {
    3. return this - b.age
    4. }
    5. fun main() {
    6. val person1 = Person("A", 3)
    7. val testInt = 5
    8. println("testInt+person1=${testInt +person1}")
    9. }

    输出结果
    testInt+person1=2

    运算符在Kotlin中是有数量上限的,当kotlin中已有的运算符不能满足我们使用的时候,我们需要对运算符进行扩展,这里就用到了中缀表达式(如step),定义中缀表达式使用关键字:infix

    infix 类型.函数() 是中缀函数的声明形式,就是扩展函数前面使用了indfix关键字,函数签名的类型,称为函数的接收者类型,换言之只有该类型才能调用这个函数。

    中缀也可以被通过正常的函数调用来使用:类对象.中缀函数()

    1. sealed class CompareResult{
    2. object More : CompareResult(){
    3. override fun toString(): String {
    4. return "大于"
    5. }
    6. }
    7. object Less : CompareResult(){
    8. override fun toString(): String {
    9. return "小于"
    10. }
    11. }
    12. object Equal : CompareResult(){
    13. override fun toString(): String {
    14. return "等于"
    15. }
    16. }
    17. }
    18. infix fun Int.vs(value : Int) : CompareResult =
    19. if(this - value > 0){
    20. CompareResult.More
    21. }else if(this - value < 0){
    22. CompareResult.Less
    23. }else{
    24. CompareResult.Equal
    25. }
    26. fun main(){
    27. println(5 vs 6)
    28. println(8.vs(7))
    29. }

    需要注意一点是,如果在一个类中重载了别的类的运算符,那么这个重载运算符仅能在这个类及其子类中使用,在这个类的外部、派生类、object修饰的类均不能使用

    13,解构

    kotlin允许将一个类拆解,并分别赋值。

    1. class User(var name:String, var age:Int){
    2. operator fun component1() = name //这里的operator是约定的意思,就是约定name是component1()
    3. operator fun component2() = age
    4. }
    5. fun main(){
    6. var(name, age) = User("111",2)
    7. println("name = $name, age = $age")
    8. }

    解构常用于遍历MAP和List中,能够一次性拿到所有值

    1. val map = mapOf("key1" to "value1", "key2" to "value2", 3 to "value3")
    2. for((key, value) in map){
    3. println("$key----------------$value")
    4. }
    5. //使用map的话可以直接拿 index和value,使用list必须使用withIndex()
    6. val list = arrayListOf("1", "2", "3", "4")
    7. for((index, value) in list.withIndex()){
    8. println("index = $index, value = $value")
    9. }

    14,typealias

    这个类似于C/C++上面的typedef,将一个类映射到另一个类上,不同点C/C++是宏定义展开,在Kotlin中是完全映射。用于在跨平台上有一个更好的兼容性

    Android JNI1--C语言基础_袁震的博客-CSDN博客

    1. public typealias 别名 = 映射到的对象
    2. //给File类创建了一个别明类TestFile, 使用TestFile与使用File是完全一样的
    3. public typealias TestFile = File

    这个特性被广泛运用在各种集合的定义中,比如Kotlin的HashMap其实就是映射的java的HashMap

    @SinceKotlin("1.1") public actual typealias HashMap = java.util.HashMap

    15,Callback

    1. public interface JavaCallback {
    2. void show(String info);
    3. }
    1. public class JavaManager {
    2. public void setCallback(JavaCallback javaCallback) {
    3. javaCallback.show("yuanzhenjava");
    4. }
    5. }
    1. interface KTCallback {
    2. fun show(name: String)
    3. }
    1. class KtManager {
    2. fun setCallback(callback: KTCallback) {
    3. callback.show("yuanzhen")
    4. }
    5. }

    kotlin调用java CallBack:

    1. //第一种写法
    2. JavaManager().setCallback(JavaCallback {
    3. println(it)
    4. })
    5. // 第二种写法
    6. JavaManager().setCallback(object : JavaCal
    7. override fun show(info: String?) {
    8. println(info)
    9. }
    10. })
    11. // 第三种写法
    12. val callback = JavaCallback {
    13. println(it)
    14. }
    15. JavaManager().setCallback(callback)
    16. // 第四种写法
    17. val callback2 = object : JavaCallback{
    18. override fun show(info: String?) {
    19. println(info)
    20. }
    21. }
    22. JavaManager().setCallback(callback2)

    kotlin调用kotlin CallBack

    1. //第一种写法
    2. KtManager().setCallback(object : KTCallback{
    3. override fun show(name: String) {
    4. }
    5. })
    6. // 第二种写法
    7. val c = object : KTCallback{
    8. override fun show(name: String) { }
    9. }
    10. KtManager().setCallback(c)

    16,Lambda表达式

    最基本的lambda表达式格式:

    1. val lambda表达式名称 : (参数类型,...) -> (返回值类型)={参数名称,... -> 函数实现(返回值)}
    2. val lambda闭包名称 = { 参数名称:类型 -> 函数实现(返回值) }

    调用:

    1. 闭包名称.invoke(参数列表)
    2. 闭包名称(参数列表)

    下面来看使用:

    这种情况不能调用,因为没有具体的实现,但是可以定义

    再来看这种情况:

    1. val method2 :(Int, Int)-> Int
    2. method2(1,2)

    这种情况可以调用吗? 

    答案是不能,因为它虽然有入参和返回值,但是依然没有具体实现

    再来看下面的例子:

    1. val method : (Int,Int) ->Int ={a,b->a+b}
    2. println("${method(1,2)}")

    这种情况是可以调用的,并且输出3

    因为它有具体的实现

    下面来看一下lambda表达式的第二种写法:

    1. val method3 ={a:Int ,b:Int ->a+b}
    2. println("${method3.invoke(1,2)}")
    3. println("${method3(2,3)}")

    输出3  5

    这种写法还可以自动转型:

    1. val method4 ={a:Int ,b:Int ->a.toDouble()+b.toDouble()}
    2. println("${method4(2,3)}")

    输出5.0

    :格式返回空的写法:

    1. val method5 : (String,String) ->Unit ={a,b-> println("a:$a,b:$b") }
    2. method5("yuan","zhen")

    输出:a:yuan,b:zhen
    再来看一个例子:

    1. val method6 : (Int) ->String ={
    2. when(it){
    3. in 1 ..200 ->"在1到200 之间"
    4. in 201 ..300 ->"在201到300之间"
    5. else ->"在300以上"
    6. }
    7. }
    8. println(method6(120))

    输出:在1到200 之间

    再来看一个最简洁的使用:

    1. val method7 ={ println("method7") }
    2. method7()

    lambda表达式可以进行覆盖操作:

    1. var method8 ={a:Int, b:Int -> println("$a,$b") }
    2. method8 ={ a:Int, b:Int ->println("覆盖了") }
    3. method8(1,2)

    输出:覆盖了

    如果想要打印,并且想要返回值,怎么操作?

    1. var method9 ={a:Int -> println("$a")
    2. a
    3. }
    4. println("结果:${method9(10)}")

    输出:10  结果:10

    会返回最后一行的结果,如果是空,返回Unit

     Lambda闭包三原则:

    ①,如果lamdba闭包没有参数,可以省略箭头符号(仅写实现部分);如果lamdba仅有一个参数,可以省略声明,并在使用时使用`it`来代替

    ②,如果lambda闭包是函数的最后一个参数,则可以将大括号放到小括号(函数名称的小括号)外

    ③,如果函数只有一个参数并且这个参数是lambda,则可以省略小括号

    下面来看一个例子:

    1. val txt = findViewById(R.id.txt)
    2. txt.setOnClickListener(object :View.OnClickListener {
    3. override fun onClick(v: View?) {
    4. println("${v?.id}")
    5. }
    6. })

    如果我们用lambda表达式来写的话:

    txt.setOnClickListener({v->println("${v?.id}")})

    如果使用原则①的话:

    txt.setOnClickListener({println("${it?.id}")})

    如果使用原则②的话:

    txt.setOnClickListener(){println("${it?.id}")}

    如果使用原则③的话:

    txt.setOnClickListener{println("${it?.id}")}

    17,高阶函数

    函数的参数或者函数返回值是Lamdba闭包的函数,我们称之为高阶函数

    Kotlin的高阶函数有点类似于C++的函数指针

    光说字面意思,我们可能会有点懵,下面我们就来看一个简单的高阶函数用法:

    拿一个简单的登录操作来说,正常写法是:

    1. fun login(name:String,pwd :String):Boolean{
    2. if (name == "yuanzhen" && pwd == "123") {
    3. println("登陆成功")
    4. return true
    5. } else {
    6. println("登录失败")
    7. return false
    8. }
    9. }
    10. val result =login("yuanzhen","123")
    11. println(result)

    输出登录成功 true

    如果用高阶函数怎么来写呢?

    1. fun login1(name: String,pwd: String, yy: (String,String)->Boolean){
    2. yy(name,pwd)
    3. }
    1. login1("yuanzhen","123",{name,pwd ->
    2. if (name == "yuanzhen" && pwd == "123") {
    3. println("登陆成功")
    4. true
    5. } else {
    6. println("登录失败")
    7. false
    8. }
    9. })

    输出:登录成功

    这样使用起来比较麻烦,我们可以使用typealias来定义lambda参数名称

    1. typealias LambdaMethod =(String,String)->Boolean
    2. fun login2(name:String,pwd:String){
    3. login1(name,pwd){name,pwd->
    4. if (name == "yuanzhen" && pwd == "123") {
    5. println("登陆成功")
    6. true
    7. } else {
    8. println("登录失败")
    9. false
    10. }
    11. }
    12. }
    13. fun login1(name: String,pwd: String, yy: LambdaMethod){
    14. yy(name,pwd)
    15. }

    调用:

    login2("yuanzhen","123")

    下面我们来给一个万能的类型增加一个扩展函数

    1. fun T.outMethod(yy: T.() ->T){
    2. println(yy())
    3. }
    1. val name ="yuanzhen"
    2. val age =30
    3. fun main() {
    4. name.outMethod {
    5. if(this =="yuanzhen"){
    6. "22222"
    7. }else{
    8. "33333"
    9. }
    10. }
    11. age.outMethod {
    12. if(this ==30){
    13. 30
    14. }else{
    15. 20
    16. }
    17. }
    18. }

    输出:22222  30 

    是不是有点懵?

    下面我们来解释一下:

    T.outMethod() 是一个扩展函数,yy: T.() ->T 是一个lambda表达式,作为参数,就是高阶函数了

    T.()是一个匿名函数,就相当于this

    println(yy())就相当于调用了参数yy

    因为T是任意类型的,所以name和age都可以调用。

    this在name中,就是"yuanzhen" 在age中,就是30。

    再来看一个升级版的用法:

    fun  T.outMethod1(yy: T.() ->R):R = yy()
    1. val name1 =name.outMethod1 {
    2. if(this=="yuanzhen"){
    3. 80
    4. }else{
    5. 10
    6. }
    7. }
    8. println("name1:$name1")

    输出:name1:80
    这个相当于给方法outMethod1增加了一个返回值,返回值与yy一样

    下面继续升级:

    1. fun T.outMethode2(yy: T.(T) -> R):R =yy(this)
    2. val name2 =name.outMethode2 {
    3. println(this)
    4. println(it)
    5. 200
    6. }
    7. println(name2)

    输出: 

    yuanzhen
    yuanzhen
    200

    所以,我们可以看到,在这里,this和it是一样的

    上面的高阶函数,我们还可以链式调用

    1. val name2 =name.outMethode2 {
    2. println(this)
    3. println(it)
    4. 200
    5. }.outMethode2 {
    6. 100
    7. }.outMethode2 {
    8. "1111"
    9. }
    10. println(name2)

    输出:

    yuanzhen
    yuanzhen
    1111

    下面我们来一个实战: 自定义一个线程

    1. fun myThread(yy:() ->Unit) :Thread{
    2. val thread =object :Thread(){
    3. override fun run() {
    4. super.run()
    5. yy()
    6. }
    7. }
    8. thread.start()
    9. return thread
    10. }
    1. myThread {
    2. name.outMethode2 {
    3. println(this)
    4. println(it)
    5. 200
    6. }
    7. }

    关于高阶函数,就讲这么多,更多的是自己去敲,去想怎么使用,光看的话很容易蒙圈。

    总结

    kotlin的高阶用法差不多就是上面这些,关于协程,可以查看文章

    Android Kotlin 协程详解_袁震的博客-CSDN博客

  • 相关阅读:
    java-net-php-python-jspm校园闲置物品拍卖系统计算机毕业设计程序
    English语法_定语从句 - 限定性与非限定性
    INTERSPEECH 2022 | 钉钉蜂鸣鸟音频实验室论文入选国际顶会,创新提出窄带滤波网络架构
    DES算法揭秘:数据加密的前沿技术
    仅靠阿里 P9 分享的 Redis 工作手册,拿到 60W 年薪 Offer
    【DDR3 控制器设计】(6)DDR3 的读写模块添加 FIFO 接口设计
    监控系统典型架构
    【c++百日刷题计划】 ———— DAY9,奋战百天,带你熟练掌握基本算法
    到底是选择极米还是选择当贝?画质看当贝,音质看极米 在意画质和使用体验的选当贝
    新闻 | 虹科电子与rooom正式建立合作伙伴关系
  • 原文地址:https://blog.csdn.net/y2653904/article/details/132963496