Kotlin学习---高阶

上一节我们学习了Kotlin的一些基础语法包括和java语言的一些区别,虽然说java和kotlin是无缝对接,但是他们彼此之间相互调用还有一些需要注意的地方,

一、java与Kotlin互相调用

1、kotlin调用java时,需要做非空的判断处理,这样避免出现空指针异常

2、kotlin调用java的接口,可以使用(object : javaCallback )进行实例化后实现接口的方法

                                    可以直接使用({这里显示接口方法的函数体})

                                      直接创建接口的的实例,并实现接口

3、java调用kotlin的方法,可以通过文件的名.方法名来进行调用,但是如果不想让java调用,可以使用双单引号将方法名字包含起来就无法调用了

fun 'show'(){
    //此方法无法被java调用
}

4、kotlin中的扩展函数(就是可以在任何地方为一个类扩展一个函数)

class student{
}

//此时为student添加了一个扩展函数
fun student.add(var number:Int,var number2:Int){
}

fun main():Int{
student.add(1,2);
}

5、kotlin泛型

1)java中泛型的通配符是? 而Kotlin泛型的通配符是 *

2)kotlin 中的out 相当于java是 extends 只读 输出

                in   相当于java是 super    只写   输入
open class fuclass {
    var name1 = "fuclass"
}

class ziclass : fuclass() {
    var name = "ziclass"
}
fun main() {

    /**
     * TODO in out 的读写模式
     */
    var list: MutableList<out fuclass> = ArrayList<ziclass>()
    var temp = ziclass()
//    list.add(temp)//不能修改  报错
    var item1 = list.get(0)//获取

    var list2: MutableList<in ziclass> = ArrayList<fuclass>()
//    list2.add(fuclass())
    var item = list2[0]
    println("name=${(item as ziclass).name},name1=${item.name1}")

}

3) in out 在类的声明泛型时作用:可以控制整个类泛型读写模式, 而java中不能在泛型声明的时候限定泛型的读写模式

  n 说明该类的泛型只能写     相当于输入,就是只写的

  out 说明该类的泛型只能获取  相当于输出,就是只读的

  不使用in out 说明该类的泛型既可以输入,也可以输出
//在声明泛型时候的泛型读写模式的限定
class Student<in T> {
    //可写
    fun setData(data: T) {
    }
    //不可读,报错
    fun getData(): T?{
        return null
    }
}

class Teacher<out T> {
    //不可写,报错
//    fun setData(data: T) {
//    }

    //可读
    fun getData(): T? {
        return null
    }
}

二、高阶函数

概念:将函数作为参数传递给主函数,该主函数称为高阶函数。

高阶函数在kotlin中随处可见,想要深刻理解高阶函数,需要先来学习一下lambda表达式,这样就让你学起高阶函数了达到事半功倍的效果。

2.1)lambda表达式

1、:() 括号中是参数

2、={} 括号中是函数体

3、var 变成val 后就不可以覆盖了

4、只有一个参数时可以不写(默认是it),多个参数则需要写清楚

//() 参数为空,返回值:Unit   函数名method , 该函数不能调用,因为没有函数体
var method:()->Unit

//有函数体,可以调用
var method1:(Int ,Int)->Int={number1+number2=number1+number2}
method1(9,9)

var method3={number1:Int,number2:Int-> number1+number2}

//只有一个参数
var m10 : (Int) -> Unit = {
        when(it) {
            1 -> println("你是一")
            in 20..30 -> println("你是 二十 到 三十")
            else -> println("其他的数字")
        }
    }
    m10(29)

//无参数
 var m12 = { println("我就是m12函数,我就是我") }
    m12()


 // 覆盖操作
  var m14 = {number: Int -> println("我就是m14  我的值: $number")}
    m14 = {println("覆盖  我的值: $it")}
    m14(99)

2.2)高阶:

1、高阶函数的最后一个参数是一个函数时,在实现函数体时 可以在函数参数括号外使用{}来实现函数参数的函数体

2、使用typealias 来给高阶函数起一个别名 typealias LOGIN= (String, String) -> Unit 他就像一个数据类型一样的使用

3、当函数参数只有一个参数时,可以直接使用{}进行闭包,默认将一个参数命名为it,
有多个参数时,无法默认 则需要指明参数名,并用->指向函数体

4、 如果函数参数已经有了实现体,那么可以通过:: 来直接调用;

:: 内部原理:就是将show_run函数的对象赋值给show_14的参数,那么说明show_run 是可以赋值给一个变量的

下面是typealias 的使用:

//类似于typedef
typealias LOGIN = (String, String) -> Unit

fun main(){
      fun loginService(username: String, password: String, login: (String, String) -> Unit) {
        login(username, password)
    }
    
    
     //高级别名的使用
    fun loginService2(username: String, password: String, login: LOGIN) {
        login(username, password)
    }
    
    //真正使用
    fun loginEngine(username: String, password: String): Unit {
        loginService(username, password) { username, pwd ->
            //此处就是高阶函数的函数体
            println("username=${username},pwd=${password}")
        }
    }
     loginEngine("leon", "123456")
}

下面是一个或多个参数的使用:

fun main(){
 //  多个参数的函数参数
    fun show(mm: (String) -> Unit) {
        mm("一个参数")
    }

    show {
        println("一个参数的函数参数:$it")
    }

    fun show1(mm: (String, Int) -> Unit) {
        mm("多个个参数", 1)
    }
    //下面是调用
    show1 { param1, param2 ->
        println("多个参数的函数参数:param1=$param1,param2=$param2")
    }
}

下面是::来调用

fun main(){
 // :: 来调用高阶的函数参数

    fun show_14(number: Int, mm: (Int) -> String): String {
        return mm(number)
    }

    fun show_run(number: Int) = "通过:: 来调用函数参数的实现函数_$number"

    //
    val showRunObj = ::show_run
    println(show_14(50, showRunObj))
    println(show_14(100, ::show_run))
}

2.3) 高阶里面的手写标准

1、kotlin中的泛型除了数据类型,还包含了方法,方法也算一个类型,即万能类型

2、T 是泛型,R是返回类型的泛型

3、T.MyRun相当于给泛型T增加了一个MyRun的扩展函数, mm: T.() -> R 代表给T增加一个匿名的扩展函数

4、类似于RxJava中的链式调用

fun main(){
fun <T, R> T.MyRun(mm: () -> R): R {
        return mm()
    }

    //给T增加一个匿名函数 T.()
    fun <T, R> myWith(input: T, mm: T.() -> R): R {
        return input.mm()
    }

    var age = 0
    age.MyRun {
        "headworld"
    }

    var name = "Leon"
    myWith(name) {
        length//此时可以直接获取name的长度
    }
}

2.4 高阶里面的标准特色:let、apply 、also、run、with、takeIf、takeUnless、repeat

kotlin给我们提供了很多类似的标准,可以参考Standard.kt里面的自己去学习,

  1. let : 其实就是将调用类型的对象自己作为参数传递给block的函数体

  2. apply: 其实就是在执行完block函数后,将apply的调用者返回,类似于建造者模式的链式调用

  3. also:将当前调用者作为参数传递给block函数,并将调用者作为返回值返回,便于链式调用

  4. run: 将调用者作为参数传递给block函数,并将block执行的结果返回

5)with:使用指定的receiver作为接受者调用block函数后,将block函数执行的结果返回

6)takeIf:当调用者满足predicate的条件时返回调用者,不满足时返回null

 takeUnless: 和takeIf正好相反

7)repeat: 其实就是系统提供出来的一个轮询器,方便我们遍历数组

    var Leon = "Leon"
    Leon.let {
        println("let 参数it的值是${it}")
    }

    var temp = Leon.apply {
        println("apply 回传的this的值是$this")
    }
    println("apply 执行后的结果$temp")

    repeat(Leon.length) {
        println("repeat轮询:it=${it},leon的当前位置的字符是:${Leon[it]}")
    }

//输出的结果如下:
//let 参数it的值是Leon
//apply 回传的this的值是Leon
//apply 执行后的结果Leon
//repeat轮询:it=0,leon的当前位置的字符是:L
//repeat轮询:it=1,leon的当前位置的字符是:e
//repeat轮询:it=2,leon的当前位置的字符是:o
//repeat轮询:it=3,leon的当前位置的字符是:n

虽然kotlin给我们提供了很多标准,其实我们还是可以自己定义我们所需要的的标准的,下面来模仿一下系统的repeat 做一个自定义

说明:

1)我们在使用下标的时候,下标从0 开始,所有这里在执行轮询的时候,需要使用区间,但是必须until 去掉尾部,否则会多执行一次

2)step 后面的步长,必须要明确说明,不能作为参数来进行赋值

3)真正的操作是在action这个函数参数的函数体内完成

 fun main(){
 
 fun doWhile(count: Int, action: (Int) -> Unit) {
        for (index in 0 until count step 1) {
            action(index)
        }
    }

    doWhile(10) {
        println("自定义轮询器的下标:$it")
    }
}


//输出结果如下:
自定义轮询器的下标:0
自定义轮询器的下标:1
自定义轮询器的下标:2
自定义轮询器的下标:3
自定义轮询器的下标:4
自定义轮询器的下标:5
自定义轮询器的下标:6
自定义轮询器的下标:7
自定义轮询器的下标:8
自定义轮询器的下标:9

2.5)自定义线程的封装

1)我们分封装的线程,这样后续我们可以直接值关心耗时操作即可,

2) openThread 可以作为一个模板来使用

 fun openThread(start: Boolean, RunTask: () -> Unit): Thread? {
        val thread = object : Thread() {
            override fun run() {
                super.run()
                RunTask()
            }
        }
        return if (start) {
            thread.start()
            thread
        } else {
            null
        }
    }
    
    fun main(){
       //对比系统的thread代码,大体类似

    openThread(true) {
        println("我是在子线程中执行的耗时操作:输出字符串")
    }
    }

今天我们主要学习了一下kotlin和java互相调用时一些需要注意的点,着重学习了kotlin中的高阶和自定义标准模板,希望对各位看官有所帮助。

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,884评论 6 492
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,347评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,435评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,509评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,611评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,837评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,987评论 3 408
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,730评论 0 267
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,194评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,525评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,664评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,334评论 4 330
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,944评论 3 313
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,764评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,997评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,389评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,554评论 2 349

推荐阅读更多精彩内容