Kotlin从0到1,让你一周快速上手!!

声明

大家好,这里是懒羊羊学长,如果需要pdf版以及其他资料,请加入群聊。群里每天更新面经、求职资料,经验分享等,大家感兴趣可以加一下。
在这里插入图片描述

Kotlin

    • 声明
    • 1.Kotlin基础
    • 2. Kotlin函数
    • 3.Kotlin进阶
    • 4.Kotlin集合
    • 5.Kotlin高级
    • 6.kotlin实战
      • 6.1协变 逆变
    • 7. 手写内置函数
      • 7.1 Kotlin的单例模式
      • 7.2 Kotlin的注解
      • 7.3 手写RxJava

1.Kotlin基础

  • Kotlin的空指针检查
    var name:String?=null
    //村民1使用null
    //TODO 第一种补救措施,变量后边加上?,这样的话name如果真的是null,后边就不会执行,就不会引发空指针异常
    name?.length
    //TODO 第二种补救措施,不论name是不是null,都会执行
    name!!.length

    //TODO 第三种补救措施 ,(和Java一样)
    if(name!=null){
        name.length
    }

  • var 和val
 //TODO val修饰的变量只读不能改  var修饰的变量可读可改  我们修饰变量时尽可能用val修饰
  • 类型推断(函数也可以类型推断)
fun main(){
   //TODO 类型推断
    val name:String="Derry"
    val info:String ="真的很帅"

    val name1="Derry"
    val age=35
    val sex='c'
    //kotlin在编译期就决定好了类型,那么他就是静态语言。
}
fun add(number1:Int,number2:Int)=number1+number2
  • Java中称为方法,kotlin中称为函数,可以写在类的外面

  • Kotlin内置数据类型 这些在Java里边相当于一个包装类
    String 字符串
    Char 单字符
    Boolean true、false
    Int 整数
    Double 小数
    List 元素集合
    Set 无重复的元素集合
    Map 键值对的集合

  • 编译时常量

const val PI=3.14 //编译时常量,不能放在函数里边。如果在函数里边的话只能在运行时运行,何来编译时常量之说。
fun main(){
    val infoValue="Derry is Ok" //这个是只读类型的变量,并不能成为编译时常量
    println(infoValue)//只能读取,只读类型


}
  • kotlin引用数据类型
const val PI=3.14 //编译时常量,不能放在函数里边。如果在函数里边的话只能在运行时运行,何来编译时常量之说。
fun main(){
    val infoValue="Derry is Ok" //这个是只读类型的变量,并不能成为编译时常量
    println(infoValue)//只能读取,只读类型


}
  • range表达式
package com.example.myapplication.kotlinlearn
//TODO  kotlinrange表达式讲解
class kt13 {


}
fun main(){
    val number=148

    //range 范围从哪里到哪里
    if(number in 10..59){
        println("分数不及格")
    }else if(number in 0..9){
        println("分数不及格并且分数很差")
    }else if (number in 60..100){
        println("分数合格")
    }else if (number !in 0..100){
        println("分数不在1到100范围内")
    }
}
  • when表达式
package com.example.myapplication.kotlinlearn

//TODO when表达式详解
class kt14 {
}

fun main() {
    //Java中if语句是执行代码
    //Kotlin中是表达式,能够有返回值
    val week = 1
    val resultInfo = when (week) {
        1 -> "星期一"
        2 -> "星期二"
        3 -> "星期三"
        4 -> "星期四"
        5 -> "星期五"
        6 -> "星期六"
        7 -> "星期日"
        else -> "不知道星期几了"
    }
    println(resultInfo)
}
  • String模板
package com.example.myapplication.kotlinlearn

class kt15 {
}

//TODO 15.String 模板
fun main() {
    val garden = "梅溪湖公园"
    val time = 6

    println("今天天气很晴朗,去玩" + garden + "玩了" + time + "小时")//Java的写法
    println("今天天气很晴朗,去玩$garden,玩了${time}小时")//String模板的写法
    //KT是表达式
    println()
    val isLogin = false
    println("resposne result:${if (isLogin) "恭喜" else "不恭喜"}")
}

2. Kotlin函数

  • 函数格式
package com.example.myapplication.kotlinlearn02

class K1Base {
}

//TODO 16.Kotlin的函数头讲解
fun main() {
    method01(1, "33")
}

//函数不加修饰符的话默认就是public
//kotlin函数是先有输入,再有输出
private fun method01(age: Int, name: String): Int {
    println("name$name,age:$age")
    return 200
}
  • 默认参数
package com.example.myapplication.kotlinlearn02

class K1Base {
}

//TODO 16.Kotlin的函数头讲解
fun main() {
    method01(1, "33")
}

//函数不加修饰符的话默认就是public
//kotlin函数是先有输入,再有输出
private fun method01(age: Int, name: String): Int {
    println("name$name,age:$age")
    return 200
}
  • 具名函数参数
package com.example.myapplication.kotlinlearn02

class K1Base {
}

//TODO 16.Kotlin的函数头讲解
fun main() {
    method01(1, "33")
}

//函数不加修饰符的话默认就是public
//kotlin函数是先有输入,再有输出
private fun method01(age: Int, name: String): Int {
    println("name$name,age:$age")
    return 200
}
  • Unit关键字
package com.example.myapplication.kotlinlearn02

class kt19 {
}

//TODO KotlinUnit函数的特点
fun main() {
    val r: Unit = doWork()
    println(r)

}

//:Unit不写默认也有,相当于无参数返回 忽略类型 相当于Java里的void,Unit是一个类型 不是关键字
private fun doWork(): Unit {

}
  • Nothing关键字
package com.example.myapplication.kotlinlearn02

class kt19 {
}

//TODO KotlinUnit函数的特点
fun main() {
    val r: Unit = doWork()
    println(r)

}

//:Unit不写默认也有,相当于无参数返回 忽略类型 相当于Java里的void,Unit是一个类型 不是关键字
private fun doWork(): Unit {

}
  • 反引号的使用
package com.example.myapplication.kotlinlearn02
//TODO kotlin反引号特点讲解

class kt21 {
}

private fun a() {
    //1 '方法名' 用反引号写的kotlin方法名在低版本的时候是可以使用的,但先高版本已经废弃了
    kt21.`is`()//如果别的Java文件里恰好定义了这两个方法,那么得用反引号括起来
    kt21.`in`()

    //3.第三种情况

    //private fun `2123456`(){  加密函数作用,维护一个文档,里边写明这个函数的饿作用
    //
    //}

}

private fun `2123456`() {

}
  • 匿名函数
package com.example.myapplication.kotlinlearn02

//TODO 22.匿名函数讲解
fun main() {
    //没有名字的函数是匿名函数
    val length = "derry".count() {//  由于没有名字,会默认给这个Char类型,一个名字,一般情况下 都是it。传入参数是把字符串的每一个字符依次传入进来
        it == 'r'

    }
    println(length) //这里会打印出2,因为字符串中只有两个字符是满足lambda表达式的条件

}
  • Kotlin函数类型
package com.example.myapplication.kotlinlearn02

class kt23 {
}

//TODO 23.Kotlin的函数类型和隐式返回讲解
fun main() {
    val methodAction: () -> String//函数的输入与输出的声明  声明区域
    methodAction = { //实现区域
        "xyr" //匿名函数不用写return 以最后一行作为返回值
    }

    //调用函数
    println(methodAction())
    println(methodAction.invoke()) //这种调用方式仅限于lambda,普通函数就不支持这种方式了
}

fun methodAction(): String //声明区域
{
    return "xyz" //实现区域
}
  • lambda函数的参数
package com.example.myapplication.kotlinlearn02

fun main() {
    //第一步:函数输入  输出 和声明,第二步是函数的实现
    val methodAction: (Int, Int, Int) -> String = { number1, number2, number3 -> //大括号里是函数的实现
        "number1:$number1,number2:$number2"
    }

    //第三步调用
    println(methodAction(1, 2, 3))
}

//真正的函数
fun methodAction(number1: Int, number2: Int, number3: Int) {

}
  • it关键字的用法
package com.example.myapplication.kotlinlearn02

fun main() {
    //第一步:函数输入  输出 和声明,第二步是函数的实现
    val methodAction: (Int, Int, Int) -> String = { number1, number2, number3 -> //大括号里是函数的实现
        "number1:$number1,number2:$number2"
    }

    //第三步调用
    println(methodAction(1, 2, 3))
}

//真正的函数
fun methodAction(number1: Int, number2: Int, number3: Int) {

}
  • 匿名函数类型推断
package com.example.myapplication.kotlinlearn02

//TODO 26.Kotlin的匿名函数类型自动推断
fun main() {
    //
    val fun2: () -> Unit
    //fun1 必须指定参数类型和返回类型
    val fun1 = {
        println("你好")
    }
    //如果没有指定,则以最后一行作为返回值类型
    val fun3 = { v1: Double, v2: Float, v3: Int ->
        "啦啦啦v1$v1,v2$v2,v3$v3"
    }
    //fun3 就是(Double,Float,Int)->String 这个类型  ,fun4并不是匿名函数,只是一个变量,后边的函数体才是匿名函数
    println(fun3(2.2, 3f, 5))
    fun1.invoke()
}
  • lambda表达式
package com.example.myapplication.kotlinlearn02

//TODO 27.Kotlin的lambda的表达式
fun main() {
    //匿名函数
    val fun1 = {

    }

    //匿名函数等价于后边要讲的Lambda
    val addResultFun = { number1: Int, number2: Int ->
        println("两个数相加的结果是${number1 + number2}")
    }
    val weekResult: (Int) -> Any = { number: Int ->
        when (number) { //when关键字也可以作为一个返回值
            1 -> "星期一"
            else -> -1
        }
    }
}
  • 函数中定义参数是函数包函数
package com.example.myapplication.kotlinlearn02

//TODO 28.函数中定义参数是函数包函数
fun main() {
    //用户
    loginAPI("Derry", "123456") { msg, code ->
        println("用户最终登录的成果如下msg:$msg,code是:$code")

    }
}

//模拟:数据库SQLServer
const val USER_NAME_SAVE_DB = "Derry"
const val USER_PWD_SAVE_DB = "123456"

//模拟,登录API前端
public fun loginAPI(userName: String, userPwd: String, responseResult: (String, Int) -> Unit) {
    if (userName == null || userPwd == null) {
        TODO("用户名密码是null")
    }
    responseResult.invoke(userName, 3)
}
  • 内联函数
package com.example.myapplication.kotlinlearn02

//TODO 内联函数
fun main() {
    //TODO 如果函数没有内联,那么在调用端,会生成多个对象来完成Lambda的调用(会造成性能的损耗)
    //TODO 如果此函数使用内联,在调用端会采用宏替换,替换到调用处,好处(没有任何函数开辟、对象开辟等性能的损耗)
    //如果一个函数里的参数有Lambda,那么,就需要声明内联

    //TODO 如果函数参数有Lambda,尽量使用inline修饰,这样内部会做优化,减少函数、对象开辟的损耗。
}
  • 函数引用
package com.example.myapplication.kotlinlearn02

//TODO 31,函数引用类型调用
fun main() {
    //方式一
    login("张三", "123") { msg, code ->
        {

        }
        //函数引用环节  ,函数通过函数引用::来变成函数类型的对象
        login("张三", "李四", ::responseResultImp)

    }
}

fun responseResultImp(msg: String, pwd: Int): Unit {

}

inline fun login(name: String, pwd: String, resposneResult: (String, Int) -> Unit) {

}
  • Kotlin中函数类型作为返回值类型
package com.example.myapplication.kotlinlearn02

//TODO 32.Kotlin的函数类型作为返回类型
fun main() {

    val result = showFun("你好")//result是个函数类型
    result("dd", 3)

}

fun show(info: String): Boolean {  //函数返回Boolean值
    return false;
}

fun showFun(info: String): (String, Int) -> String {
    println("我是show函数info:$info")
    return { name, age ->
        "name=$name,age=${age}"
    }
}
  • 匿名函数和具名函数
package com.example.myapplication.kotlinlearn02

//TODO 33.Kotlin中的匿名函数和具名函数
fun main() {
    //匿名函数
    showPersonInfo("Derry", 38, '男', "学习KT语言中") {
        println(it)
    }
    println()
    //具名函数
    showPersonInfo("Derry", 38, '男', "学习KT语言中", ::showResultImpl)

}

fun showResultImpl(it: String) {
    println("显示具名:$it")
}

inline fun showPersonInfo(
    name: String,
    age: Int,
    sex: Char,
    study: String,
    showResult: (String) -> Unit
) {
    val str = "name:$name,age:$age,sex:$sex,study:$study"
    showResult(str)//这个lambda只是起了一个名字,并不是一个真正的函数,真正的实现是上边的println语句

}
  • kotlin可空的特性
package com.example.myapplication.kotlinlearn03

//TODO 34.Kotlin语言可空性的特点
fun main() {
    //TODO name不能为空,如果为空,编译会报错
    var name: String = "Derry"
    //TODO 第二种情况 声明的时候指定为可空
    var name2: String? = "Derryhello"
    name2 = null
    println(name2?.length)//如果name2为null,就不执行?后边的区域
}
  • kotlin安全调用操作符
package com.example.myapplication.kotlinlearn03

import androidx.compose.ui.text.AnnotatedString
import androidx.compose.ui.text.capitalize

//TODO 35.Kotlin语言的安全调用操作符
fun main() {
    var name: String? = "xuyuanzhi"
    val c = name?.capitalize() //name是可空类型,可能是null,如果想要使用name,必须给出补救措施
    //如果name是Null,就不会执行?后边的区域代码,所以就不会崩溃。
    println(c)
}
  • Kotlin中带let的安全调用
package com.example.myapplication.kotlinlearn03

//TODO 36.kotlin中使用带let的安全调用
fun main() {
    val name: String? = null
    //如果name真的是null,就不执行?.let{}这一大块区域的代码
    var r = name?.let {
        // it==name本身,所以是String类型的
        if (it.isBlank()) {
            "Default"
        } else {
            "[$it]"
        }
    }
    println(r)
}
  • Kotlin中的非空断言操作符
package com.example.myapplication.kotlinlearn03

import androidx.compose.ui.text.capitalize

//TODO 37.Kotlin语言中的非空断言操作符
fun main() {
    var name: String? = null

    name!!.capitalize()//!!是断言,不管name是不是null,都会执行.capitalize(),所以就报空指针异常了,所以要慎用

    //结论,如果百分百能够保证name是有值的,才能使用!!(否则有Java空指针异常),否则进来使用?
}
  • if判断null值的情况
package com.example.myapplication.kotlinlearn03

//TODO kotlin中使用if判断Null值情况
fun main() {
    var name: String? = null

    //if(补救措施)
    if (name != null) {
        var r = name.capitalize()
        println(r)
    } else {
        println("name is null")
    }
}
  • Kotlin的空合并操作符
package com.example.myapplication.kotlinlearn03

//TODO kotlin中使用if判断Null值情况
fun main() {
    var name: String? = null

    //if(补救措施)
    if (name != null) {
        var r = name.capitalize()
        println(r)
    } else {
        println("name is null")
    }
}
  • 异常处理与自定义异常
package com.example.myapplication.kotlinlearn03

//TODO kotlin中使用if判断Null值情况
fun main() {
    var name: String? = null

    //if(补救措施)
    if (name != null) {
        var r = name.capitalize()
        println(r)
    } else {
        println("name is null")
    }
}
  • kotlin中先决条件函数
package com.example.myapplication.kotlinlearn03

//TODO 41.kotlin中的先决条件函数
fun main() {
    val value1: String? = null
    var value2: Boolean = false

    checkNotNull(value1)  //抛个异常
    requireNotNull(value1)//

    require(value2) {
        println("我是傻逼")
    }

}


  • kotlin中的substring
package com.example.myapplication.kotlinlearn03
//TODO 42.Kotlin中的substring

const val INFO = "xyz is Success"
fun main() {
    val indexOf = INFO.indexOf('i')
    println(INFO.substring(0, indexOf))
    println(INFO.substring(0 until indexOf))
}
  • 43 kotlin中的split操作
package com.example.myapplication.kotlinlearn03

//TODO 43.Kotlin语言的split操作
fun main() {
    val jsonText = "x1,x2,x3,x4"
    val list: List<String> = jsonText.split(',')

    println("分割后的list里面的元素有${list}")

    list.forEach {
        println(it)
    }

    //C++解构 KT也有解构

    val (v1: String, v2, v3, v4) = list
    println("$v1,$v2,$v3,$v4")
}
  • kotlin中使用repace完成加密解密的操作
package com.example.myapplication.kotlinlearn03

//TODO 44.Kotlin中的replace完成加密解码操作
fun main() {
    val sourcePwd = "AbcdefdsAKMNOfafadfagg"
    println("原始密码为:$sourcePwd")

    val newPwd = sourcePwd.replace(Regex("AKMNO")) {
        "-"
    }
    println(newPwd)

    //解密操作

    val sourcePwdNew = newPwd.replace(Regex("[-]")) {
        when (it.value) {
            "-" -> "AKMNO"
            else -> it.value
        }
    }
    println("解密后的密码为$sourcePwdNew")
}
  • kotlin中==和===的比较
package com.example.myapplication.kotlinlearn03

//TODO 45.Kotlin中 ==与===的比较
fun main() {
    // ==是内容的比较。相当于Java的equals
    //===是引用的比较
    val n1: String = "aaa"
    val n2: String = "aaa"
    println(n1.equals(n2))
    println(n1 == n2)
    println(n1 === n2)
}
  • kotlin中字符串的遍历操作
package com.example.myapplication.kotlinlearn03

//TODO 46.Kotlin中字符串的遍历操作
fun main() {
    val str = "abcdefg"

    str.forEach {
        println("字符是$it")
    }
}
  • Kotlin中数字类型安全转换操作符
package com.example.myapplication.kotlinlearn03

//TODO 47.Kotlin中数字类型的安全转换函数
fun main() {
    val number: Int = "666".toInt()
    println(number)
    //如果转换成Int成功就返回Int,如果转换失败就返回Null
    val number2: Int? = "666.6".toIntOrNull()
    println(number2)
}
  • Double与Int类型相互转化
package com.example.myapplication.kotlinlearn03

import kotlin.math.roundToInt

//TODO 48.Double转Int与类型格式化
fun main() {
    println(65.4.toInt()) //toInt没有四舍五入的效果,是取低位的
    println(66.8.roundToInt())//roundToInt有四舍五入的效果,”%“

    val r: String = "%.3f".format(66.5554511)//后边保留小数点后三位
    println(r)
}

3.Kotlin进阶

  • apply函数的用法
package com.example.myapplication.kotlinlearn03

import androidx.compose.ui.text.toLowerCase

//TODO 49.Kotlin中apply的内置函数
fun main() {
    val info = "Derry is successful"
    //普通传统方式
    println(info.length)
    println("info的最后一个字符是${info[info.length - 1]}")
    println("info全部转化成小写${info.toLowerCase()}")

    //apply方式
    info.apply {
        //一般大部分情况下,匿名函数都会持有一个it,但是apply不会持有it,但会持有this     this==info本身
        //apply函数始终是返回info本身String类型
        println(this)
        println(length)
        println("info的最后一个字符是${this[length - 1]}")
        println("info全部转化成小写${this.toLowerCase()}")
    }
    //TODO apply函数的写法规则如下
    //apply函数始终返回info本身,所以可以进行链式调用
    info.apply {
        println("info的长度是${this.length}")
    }.apply {
        println("info的最后一个字符是${this[length - 1]}")
    }.apply {
        println("info全部转化成小写${this.toLowerCase()}")
        println(readLine())
    }

    //TODO 结论 apply的返回值 谁.apply,返回谁本身
    //apply里没有it,只有this,this==xxx本身
    //TODO 用法,使用中,不需要用apply的返回值,而是尽量使用链式调用,功能分层
}
  • let函数
package com.example.myapplication.kotlinlearn03

//TODO 50.kotlin语言let的内置函数
//普通方式 对集合第一个元素相加
//let方式 对集合第一个元素相加
//普通方式 对值判null 并返回
//let方式 对值判null 并返回
fun main() {
    val list: List<Int> = listOf(1, 2, 3, 4)
    val value1 = list.first()

    println(value1 + value1)

    //TODO let方式对集合第一个元素相加
    listOf(1, 2, 3, 4).let {
        //it ==集合本身
        //let作为内置函数,会以最后一行作为返回值
        it.first() + it.first()
    }

    //TODO apply总结
    //1.apply函数的返回类型 永远是调用者本身
    //2. apply函数的匿名函数体{持有的是this==info本身}
    //TODO let总结
    // 1.let函数的返回值是 函数最后一行的返回值
    // let函数持有的是it,it等于调用者本身

    //TODO 普通方式,对值判null 并返回

    //TODO let解决对值判null 并返回


}

fun get(value: String?): String {
    return value?.let {  //如果value为null 则不会执行函数体里的东西,如果不为null  ,则执行?:后边的东西
        "欢迎${value}回来"
    } ?: "你传递的是null"
}

//简化版本
fun get2(value: String?) = value?.let {  //如果value为null 则不会执行函数体里的东西,如果不为null  ,则执行?:后边的东西
    "欢迎${value}回来"
} ?: "你传递的是null"
  • run函数的综合案例
package com.example.myapplication.kotlinlearn03

//TODO 51.Kotlin语言中run内置函数
fun main() {
    //1.run函数的特点 字符串演示
    val str = "xyz is successful"

    //TODO run函数的返回,根据匿名函数
    str.run {
        //以最后一行作为返回值,run函数函数体持有this,this==调用者本身
        "a"
    }
    //TODO 2.具名函数判断长度
    //这个是匿名函数
    str.run {

    }

    //这个是具名函数,配合run
    str.run(::isLong) //this==str
        .run(::showText) //this==isLong函数返回类型Boolean的值本身
        .run(::mapTest)
        .run {
            println(this)
        }

    println()
    //TODO 上面的函数全部是具名函数调用给run运行

    str.run {
        if (length > 5) true else false

    }.run {
        if (this) "你的字符串合格" else "你的字符串不合格"
    }.run {
        "$this"
    }.run {
        println(this)
    }


}

fun isLong(str: String) = if (str.length > 5) true else false
fun showText(isLong: Boolean) = if (isLong) "你的字符串合格" else "你的字符串不合格"

fun mapTest(str: String) = "[$str]"


  • with操作符
package com.example.myapplication.kotlinlearn03

//TODO 52.kotlin中with函数
fun main() {
    //TODO 和run函数是一模一样  持有this
    val n1 = "hello"
    with(n1) {
        //this==str本身

    }

    val result1: Int = with(n1, ::getStrLenAction)
    val result2: String = with(n1, ::getStrInfo)

    //匿名操作

    with(with(n1) {
        n1.length
    }) {
        "你的字符串长度为$this"
    }

}

fun getStrLenAction(str: String) = str.length

fun getStrInfo(str: String) = str
  • also的用法
package com.example.myapplication.kotlinlearn03

import androidx.compose.ui.text.toLowerCase

//TODO also操作符
//  str.also和apply差不多,永远是返回调用者本身
fun main() {
    val str = "XUYUANZHI"
    val r1: String = str.also {

    }.also {
        //可以链式调用
        it == "a"
    }


    str.also {
        println("str的原始值是$it")
    }.also {
        println("str转换成小写的效果是${it.toLowerCase()}")
    }
}
  • takeif操作符
package com.example.myapplication.kotlinlearn03

//TODO 54.takeIf海曙的使用
fun main() {
    val name: String? = "aa"
    val result = name.takeIf {
        false
    }
    //如果为true,这个表达式返回name本身,如果为false,则返回null
    println(result)

    //企业用法,takeif+空合并操作符
    name.takeIf { true } ?: "权限不够,被拒绝访问"
}

//TODO  总结:一般大部分情况下,都是takeIf+空合并操作符


  • takeunless函数
package com.example.myapplication.kotlinlearn03

//TODO 55.takeUnless
fun main() {
    "aaa".takeUnless {
        false
    } ?: "未经过任何初始化的值"
    //takeUnless和takeif判断条件相反,但是效果一样
    //false会返回调用者本身,true会返回null
}

4.Kotlin集合

  • list的创建与获取
package com.example.myapplication.kotlinlearn03

//TODO 56.Kotlin语言的list创建与元素获取
fun main() {
    val list: List<String> = listOf("张三", "李四", "王五")
    //普通取值方式  ,索引
    println(list[0])
    println(list[1])
    println(list[2])
    println(list.get(0))
    println(list.get(1))
    println(list.getOrElse(2) { "越界" })
    println(list.getOrElse(3) { "越界了" })
    println(list.getOrNull(20))

    println(list.getOrNull(2333) ?: "你越界了哦")
    //总结:开发过程中,尽量使用getOrElse 或者  getOrNull 才能体现出Kotlin中的亮点
}
  • 可变list集合的学习
package com.example.myapplication.kotlinlearn03

//TODO 57.Kotlin可变List集合学习
fun main() {
    val list: MutableList<String> = mutableListOf("Derry", "zhangsan", "lisi")
    //可变的集合
    list.add("赵六")
    list.remove("lisi")

    println(list)
    //不可变集合
    val list2: List<Int> = listOf(123, 456, 789)

    println(list2)

    //不可变转为可变集合
    val list3: MutableList<Int> = list2.toMutableList()

    //可变集合变为不可变集合
    val list4 = list3.toList() //无法完成可变的操作
    //小结:KT语言中,分为可变集合与不可变集合 ,Kotlin中更加推荐使用不可变集合,防止造成数据丢失
}
  • mutator学习
package com.example.myapplication.kotlinlearn03

//TODO 58.Kotlin语言的mutator函数学习
fun main() {
    //1.mutator += -=操作
    val list: MutableList<String> = mutableListOf("Derry", "DerryAll", "zhangsan", "lisi")
    list += "张三"
    list -= "李四"
    println(list)

    //2.removeIf
//    list.removeIf{ //如果是true,自动遍历整个可变集合,一个一个元素的删除
//        true
//    }

    list.removeIf {
        it.contains("D")  //过滤包含D的元素
    }
    println(list)
}
  • list集合的遍历
package com.example.myapplication.kotlinlearn03

//TODO 59.List集合遍历学习
fun main() {
    val mList: List<Int> = listOf<Int>(1, 2, 3, 4, 5, 6)
    println(mList)//输出list详情而已,不是遍历集合

    //第一种遍历
    for (item: Int in mList) {
        println("item:$item")
    }

    //第二种遍历
    mList.forEach {
        //it==每一个元素
        println("item:$it")
    }

    //第三种方式

    mList.forEachIndexed { index, i ->
        println("下标是$index,值是$i")
    }
}
  • kotlin中解构语法过滤元素学习
package com.example.myapplication.kotlinlearn04

//TODO 60.Kotlin语言解构语法过滤元素学习
fun main() {
    val list: List<String> = listOf("李元霸", "李小龙", "李连杰")
    var (v1, v2, v3) = list

    var (_, va1, va2) = list //_不是变量,是用来过滤结构赋值的,拒收值,不接收赋值给我
}
  • 61Set元素的创建与获取
package com.example.myapplication.kotlinlearn04

//TODO 61.Kotlin中Set创建与元素获取
//set 定义不允许重复
//
fun main() {

    val set: Set<String> = setOf("张三", "李四", "王五", "李四")
    println(set)
    println(set.elementAt(0))
    println(set.elementAt(3))//越界 ,会崩溃
    println()

    println(set.elementAtOrElse(3) { "越界了" })

    println(set.elementAtOrNull(3)) //得不到会返回null

}
  • 可变集合set
package com.example.myapplication.kotlinlearn04

fun main() {
    val set: MutableSet<String> = mutableSetOf("李元霸", "李连杰")
    set += "张三"
    set -= "李四"
    set.remove("王五")
}
  • Kotlin集合转换和快捷函数学习
package com.example.myapplication.kotlinlearn04

//TODO 63.Kotlin语言集合转换和快捷函数学习
fun main() {
    //1.定义可变list集合
    val list: MutableList<String> = mutableListOf("张三", "李四", "王五")

    println(list)
    //2.list转set自动去重
    val set: Set<String> = list.toSet()

    println(set)
    //4.快捷函数去重distinct

    println(list.distinct())
}
  • Kotlin中的数组类型
package com.example.myapplication.kotlinlearn04
//TODO 64.Kotlin中的数组类型
// IntArray  inArrayOf
// DoubleArray  doubleArrayOf


fun main() {
    val intArray = intArrayOf(1, 2, 3, 4)

    println(intArray[1])
    println(intArray.elementAtOrNull(0) ?: "aaa")//尽量不会崩溃
    //OrNull要配合空合并操作符来使用
    println(intArray.elementAtOrElse(55) { 3 })
    //TODO 3.List集合转数组
    listOf<Char>('a', 'b', 'c', 'd').toCharArray()

}
  • map集合
package com.example.myapplication.kotlinlearn04

import androidx.compose.animation.scaleOut

//TODO 65.Kotlin中Map的创建
fun main() {
    //第一种方式
    val map1: Map<String, Double> = mapOf<String, Double>("xuyuanzhi" to 22.3, "lal" to 33.3)
    //第二种方式
    val map2 = mapOf(Pair("aaa", 33.2), Pair("ddd", 22.5))

    //TODO 读取map的值
    println(map1["xuyuanzhi"])//运算符重载了

    println(map1.get("xuyuanzhi"))//运算符重载

    //方式二
    println(map1.getOrDefault("xuyuanzhi", -1))
    println(map1.getOrDefault("xuyuanzhi") { -1 })
    //方式三,和Java一样,获取不到会崩溃
    println(map1.getValue("xuyuanzhi"))

    //TODO 遍历map的值
    //第一种方式
    map2.forEach {
        // it 每一个元素都是一个map,key value 结构。  it类型为 Map.Entry<String,Int>
        println("K:${it.key},V:${it.value}")
    }
    println()

    //第二种方式
    map2.forEach { key: String, value: Double -> //把it覆盖了
        println("key是$value,value 是 $value")

    }
    //第三种方式
    map2.forEach { (key: String, value: Double) ->
        println("key 是$key,value是$value")
    }
    //第四种方式
    for (item: Map.Entry<String, Double> in map2) {
        println("${item.key},value是${item.value}")
    }
    //TODO 可变集合Map的操作
    val map3: MutableMap<String, Int> = mutableMapOf(Pair("Derry1", 123), Pair("xuyuanzhi", 456))
    map3 += "aaa" to 23
    map3 += "BBB" to 45

    map3 -= "Derry"

    map3["cc"] = 888
    map3.put("Dddd", 999)
    //如果在map里没有找到999的元素,那么先把999添加到里边去,然后再从map里边获取999的元素
    map3.getOrPut("999") {
        66
    }

    println(map3)

}
  • Kotlin的计算属性与防范竞态条件
package com.example.myapplication.kotlinlearn04

//TODO 70.Kotlin语言的计算属性与防范竞态条件
class Derry {
    val number: Int = 0
        get() = field

    //计算属性 (field 永远是描述name的值),如果一个变量没有赋值,那么就没有field这个东西。
    //TODO 防范静态条件 当你调用成员,这个成员可能为null,可能为空值,就必须采用防范竞态条件,这个是KT编程的规范化
    // 防范静态条件尽量使用(?+内置函数+空合并操作符)
    var info: String? = null
    fun getStudentInfo(): String {
        return info?.let { //info如果不为null,则执行let函数里的,如果为null,则执行?:后边的语句
            if (it.isBlank()) {
                "你原来是空值"
            } else {
                "$it"
            }
        } ?: "info你原来是null,请检查代码"
    }//,
}

fun main() {
    //val修饰的变量 没有set函数
    Derry().number
    // 计算属性


}
  • kotlin的主构造函数
package com.example.myapplication.kotlinlearn04

//主构造函数:规范来说,都是增加_xxx的方式,临时的输入类型,不能直接用,需要接收下来,成为变量才能用
class Students(_name: String, _age: Int) {
    val name: String = _name
    fun show() {
        println("nieg")
    }
}

//TODO 71.Kotlin语言的主构造函数学习
fun main() {
    val student = Students("张三", 56)
}
  • Kolin中的构造函数
package com.example.myapplication.kotlinlearn04

class Student2(var name: String, var age: Int) { //主构造函数 ,推荐这样写
    //如果想完成多个构造函数重载的话,就用次构造才能做到
    //次构造函数必须调用主构造函数,否则编译不通过
    constructor(name: String) : this(name, 33) {

    }

    //三个参数的构造函数
    constructor(name: String, age: Int, sex: Char) : this(name, 33) {

    }

}

//TODO 构造函数的默认参数
// 主构造和次构造都有默认参数时,优先使用主构造,然后再使用次构造
class Animal(name: String = "啦啦啦") {
    val name = name

    override fun toString(): String {
        println("ddd")
        return "aa"
    }
}

fun main() {

    val s1 = Student2("张三", 18, '男') //调用三个参数的构造函数,首先会去先调用主构造函数,然后调用次构造函数
    val a1 = Animal()
    println(a1.toString())
}
  • 类的初始化顺序

在这里插入图片描述

package com.example.myapplication.kotlinlearn03

//TODO 76.Kotlin语言构造初始化顺序学习
fun main() {
    //重点:Init代码块和类成员是同时生成的,
}
  • lateinit学习 延迟初始化
package com.example.myapplication.kotlinlearn04

//TODO 77.Kolin里边延迟初始化lateinit学习
class kt77 {
    lateinit var name: String;

    fun show() {
        if (::name.isInitialized) {//判断name有没有初始化

        }
    }

    //TODO 我们再使用延迟初始化字段的时候,一定要用::name.isInitialized 这个来判断,因为这个字段一碰就会崩溃,所以不要随便用
}

fun main() {

}
  • by lazy 的使用
package com.example.myapplication.kotlinlearn04

class k78 {
    val database: String by lazy {
        "aaa"  //只有用的时候才会加载
    }
}

//TODO 78.惰性初始化by lazy
// lateinit 是在使用的时候,手动加载的懒加载方式,然后再使用
// by lazy  是在使用的时候,自动加载的懒加载方式,然后再使用
fun main() {

}
  • 崩溃小陷阱
package com.example.myapplication.kotlinlearn04

class kt79(_info: String) {
    val content: String = getInfoMethod()
    private val info = _info
    private fun getInfoMethod() = info
}

//TODO 1.陷阱一:如果init函数里要用到类属性,那么属性初始化要放在init函数之前
//  2.陷阱二:  类后边的函数要用到变量,要在这个函数之前进行初始化
// 3.陷阱三:  
// 总结:为了以后不出现陷阱三,所有的类成员都放到最前面就好了
fun main() {
    println("${kt79("Derry").content.length}")  //会崩,因为执行先执行构造方法,然后执行getInfoMentod,这个时候info还没有初始化,所以会崩


}

5.Kotlin高级

  • 继承与重载的open关键字
package com.example.myapplication.kotlinlearn05

import androidx.compose.animation.scaleOut
import com.example.myapplication.kotlinlearn04.Student2

// public final class Person
// open 去除 final修饰

open class Person(private val name: String) {  //构造参数私有化,子类不可访问
    private fun showName() = "父类的名字是$name"

    fun showName1() = "父类的名字是$name"

    open fun myPrintln(): Unit = println(showName())
}

class Student(private val subName: String) : Person(subName) {

    private fun showName() = "子类的名字是$subName"

    override fun myPrintln(): Unit = println(showName()) //此函数以及被子类重写了

}

//TODO 82.Kotlin的继承与重载的open关键字
fun main() {

    val person: Person = Student("aa")
    person.myPrintln()

    println(person is Person)
    println(person is Student)
    // is +as 配合来使用

    if (person is Student) {
        //    (person as Person).myPrintln()  这个就算转换到父类,也是调用到子类的方法
        println((person as Person).showName1())
    }

}
  • Kotlin类型转换
package com.example.myapplication.kotlinlearn05

class kt84 {
}

fun main() {
    //智能类型转换

    // xxx as xxx 从一个类型转换到另一个类型
}
  • Kotlin中Any类的超类
package com.example.myapplication.kotlinlearn05

//TODO 85.Kotlin的Any超类
// 在kt中,所有的类都隐式继承了Any(),你不写默认就有
// 在Java中,所有的类都隐式集成了 extends Object,你不写 ,默认就有
// Any在Kotlin设计中,只提供标准,看不到实现,实现在各个平台处理好了
class Person3 {

}

fun main() {

}
  • Kotlin对象声明
package com.example.myapplication.kotlinlearn05

object kt86 {

    /*
      object 对象类背后做了什么
      public static final K86 INSTANCE;
      private K86() {} //主构造废除一样的效果
      
     static  {
     
         K86 var0=new k86()
         INSTANCE =var0
         //直接把init代码搬到这里来了,因为主构造函数被私有化,所以把东西搬到这里来了
         String var1="K86 init..."
         System.out.println(var1)
      }
      public final void show(){
      }
     */
}

//TODO 86.Kotlin的对象声明
fun main() {

}
  • Kotlin中的对象表达式
package com.example.myapplication.kotlinlearn05

open class kt87 {
    open fun add(info: String) = println("K87 add: $info")
    open fun del(info: String) = println("K87 del: $info")
}

//TODO 87.Kotlin的对象表达式
fun main() {
    //TODO 匿名 对象表达式方式
    val p1: kt87 = object : kt87() {
        override fun add(info: String) {
            println("我是匿名表达方式$info")
        }

        override fun del(info: String) {
            println("我是匿名表达方式:$info")
        }
    }
    p1.add("aaa")
    p1.del("ddd")

    val p2: kt87 = k87Impl()
    p2.add("张三")
    p2.del("李四")

    //TODO 对Java的接口 用对象表达式方式
    val p3: Runnable = object : Runnable {
        override fun run() {
            println("Java Runnable run...")
        }
    }
    p3.run()
    val p4: Runnable = Runnable { //Kotlin不支持这种简洁方式,只有Java可以
        println("aaa")
    }
    p4.run()

}

class k87Impl : kt87() {
    override fun add(info: String) {
        println("我是具名函数add$info")
    }

    override fun del(info: String) {
        println("我是具名函数del${info}")
    }
}
  • kotlin中的伴生对象
package com.example.myapplication.kotlinlearn05

class kt88 {
    companion object {
        //伴生对象 ,本身是一个静态内部类
        val name = "许远志"  //直接会生成静态的 private static final String name="许远志”
        val info = "lalala是吧"
        fun showInfo() = println("显示:$info")

        // public static final kt88.companion companion =new kt88.companion()//给外界调用的

    }
}

//TODO 88.Kotlin的伴生对象,
//  伴生对象很大程度上和Java的static静态差不多的  不管kt88实例化多少次,伴生对象只加载一次,  伴生对象只初始化一次
fun main() {

}
  • 内部类
package com.example.myapplication.kotlinlearn05

//TODO 内部类
class Body() { //外部类
    val name: String = "aaa"

    class Heart { //嵌套类 加上inner修饰符才能变成内部类 ,
        val nameHeart: String = "bbb"
        fun show() {
            //println(name)
        }
    }
}

//嵌套类的特点,外部的类能访问内部的嵌套类, 内部的嵌套类不能访问外部类的成员
// 内部类的特点: 内部的类能访问外部的类  外部的类能访问内部的类
class kt89 {

    inner class kt899 {

    }
}

fun main() {
    //内部类
    kt89().kt899()
    //嵌套类
    Body.Heart()

}
  • Kotlin的数据类
package com.example.myapplication.kotlinlearn05

//普通类
class ResponseResultBean(var msg: String, var code: Int, var data: String) : Any()

//TODO set get 构造函数
//相当于接收 服务器返回的JavaBean 现在kotlin叫做数据类
data class ResponseResultBean2(var msg: String, var code: Int, var data: String) : Any()

//TODO  set get 构造函数  copy 克隆 toString hashCode  equals  结论:数据类 生成更加丰富
//TODO 90.Kotlin的数据类
fun main() {
    //TODO 1.ToString方法
    println(ResponseResultBean("aa", 12, "aa"))
    //普通类 toString 调用了windows打印的toString
    println(ResponseResultBean2("aa", 12, "aa"))
    // 数据类 any,重写了父类的toString

    //TODO 2.==方法
    //普通类==的实现  Any父类的实现 是equals  是比较两个对象的引用
    //数据类==是值的比较,所以 内容一样就是true

    //TODO 总结:普通类的Any 的== 是引用的比较  数据类any的==被重写了 是值的比较

}
  • Kotlin的解构操作
package com.example.myapplication.kotlinlearn05

//普通类
class Student1(var name: String, var age: Int, var sex: Char) {
    //解构操作 必须从component1开始
    operator fun component1() = name
    operator fun component2() = age
    operator fun component3() = sex

}

class kt92 {
}

//TODO 92.Kotlin的解构操作
fun main() {

    var (name, age, sex) = Student1("张三", 89, '男')
    //数据类默认就有解构操作

}
  • Kt的运算符重载
package com.example.myapplication.kotlinlearn05
//TODO 93.Kotlin的运算符重载

class AddClass(var number1: Int, var number2: Int) {
    operator fun plus(p1: AddClass) = (number1 + p1.number1) + (number2 + p1.number2)


}

fun main() {
    //运算符重载
    println(AddClass(2, 2) + AddClass(3, 3))
}
  • 枚举类
package com.example.myapplication.kotlinlearn05

//枚举的值等于枚举本身
enum class Week {
    星期一,
    星期二,

}

fun main() {

}
  • 枚举类型定义函数
package com.example.myapplication.kotlinlearn05

data class LimbInfo(var limbInfo: String, var length: Int) {
    fun show() = println("$limbInfo,长度是 $length")
}

enum class Limbs(private var limbsInfo: LimbInfo) {
    LEFT_HAND(LimbInfo("左手", 88)),//左手
    RIGHT_HAND(LimbInfo("左手", 88)),//左手
    ; //结束枚举值

    fun show() = "四肢是${limbsInfo.limbInfo} ,长度是${limbsInfo.length}"

    fun update(limbsInfoUpdate: LimbInfo) {
        this.limbsInfo.limbInfo = limbsInfoUpdate.limbInfo //也可以更新枚举值,这个枚举值的对象是实例化的时候传进来的
    }
}

//结论:枚举的主构造参数必须与枚举值保持一致
// 95.枚举类型定义函数
fun main() {

    println(Limbs.LEFT_HAND.show()) //枚举值的主构造参数不要管,是枚举值直接调用show来显示的

}
  • Kotlin的代数数据类型
package com.example.myapplication.kotlinlearn05

enum class Exam {
    Fraction1,//分数差
    Fraction2,//分数及格
    Fraction3,//分数良好
    Fraction4,//分数优秀
    ;//枚举结束
}

class Teacher(private val exem: Exam) {
    fun show() =
        when (exem) {
            Exam.Fraction1 -> "该学生的分数很差"
            Exam.Fraction2 -> "该学生的分数及格"
            Exam.Fraction3 -> "该学生的分数良好"
            Exam.Fraction4 -> "该学生的分数优秀"
            //不需要使用else ,由于我们的函数是用枚举类型来判断处理的,这个就属于代数数据类型,不需要写else了
            //因为when表达式非常明确了,只有四种类型,不会出现else其他,所以不需要写
        }
}

//TODO 96.Kotlin的代数数据类型讲解
//定义
fun main() {

}
  • 密封类
package com.example.myapplication.kotlinlearn05

//密封类 :在于控制子类数量可控,以免被非法继承
// 枚举类:在于控制状态数量可控
//
sealed class kt97 {
}

//TODO 97.密封类  我们的成员必须要有类型(object class)  2. 并且是继承本类
fun main() {

}
  • 数据类使用条件
package com.example.myapplication.kotlinlearn05

//TODO 98.数据类使用条件
// 数据类至少必须有一个参数的主构造函数  ;必须有val var 修饰的参数,数据类不能使用abstract,inner, open 等修饰
fun main() {

}

6.kotlin实战

  • 接口的定义
package com.example.myapplication.kotlinlearn06

interface IUSB {
    var usbVersionInfo: String //USB版本信息
    var usbInsertDevice: String// 插入的设备信息
    fun insertUSB(): String //被插入的动作
}

open class Mouse(override var usbVersionInfo: String, override var usbInsertDevice: String) : IUSB {
    override fun insertUSB(): String {
        TODO("Not yet implemented")
    }

}

class shubiao : Mouse("aa", "a"), IUSB {
    override fun insertUSB(): String {
        return super.insertUSB()
    }

}

//TODO 99.Koltin的接口定义详解
// 1.接口里面和接口本身都是public  open的,所以不需要open
// 2.接口不能有主构造
// 3.实现类不仅仅要重写接口的函数,也要重写接口的成员
// 4.接口实现代码区域要加Override来修饰
fun main() {

}
  • 接口的默认实现(只是有这个功能,很少使用)
package com.example.myapplication.kotlinlearn06

interface IUSB2 {
    val usbVersionInfo: String
        get() = "你好小白" //接口的默认实现
}

class Mouse2 : IUSB2 {
    override val usbVersionInfo: String
        get() = super.usbVersionInfo
}

// TODO 接口的默认实现
fun main() {
    val iusb: IUSB2 = Mouse2()
    println(iusb.usbVersionInfo)

}
  • Kotlin的抽象类
package com.example.myapplication.kotlinlearn06

abstract class BaseActivity {
    fun onCreate() {
        setContentView(getLayoutID())
        initView()
        initData()
        initXXX()
    }

    private fun setContentView(layoutID: Int) = println("你好啦啦啦")

    abstract fun getLayoutID(): Int
    abstract fun initView()
    abstract fun initData()
    abstract fun initXXX()

}

class MainActivity : BaseActivity() {
    override fun getLayoutID(): Int {
        return 1223
    }

    override fun initView() {

    }

    override fun initData() {
    }

    override fun initXXX() {
    }

    fun show() = super.onCreate()

}

//TODO 101-Kotlin的抽象类详解
fun main() = MainActivity().show()
  • 泛型类讲解
package com.example.myapplication.kotlinlearn06

abstract class BaseActivity {
    fun onCreate() {
        setContentView(getLayoutID())
        initView()
        initData()
        initXXX()
    }

    private fun setContentView(layoutID: Int) = println("你好啦啦啦")

    abstract fun getLayoutID(): Int
    abstract fun initView()
    abstract fun initData()
    abstract fun initXXX()

}

class MainActivity : BaseActivity() {
    override fun getLayoutID(): Int {
        return 1223
    }

    override fun initView() {

    }

    override fun initData() {
    }

    override fun initXXX() {
    }

    fun show() = super.onCreate()

}

//TODO 101-Kotlin的抽象类详解
fun main() = MainActivity().show()
  • 内置函数+泛型
package com.example.myapplication.kotlinlearn06

class kt103<T>(private val isR: Boolean, private val obj: T) {
    fun getObj(): T? = obj.takeIf { isR }
}


//TODO 103.内置函数+泛型
fun main() {
    val s1 = Student("张三", 33)
    println(kt103(true, s1).getObj())
    println(kt103(false, s1).getObj())

    kt103(true, s1).getObj().apply {
        println(this)
    }!!
}
  • Kotlin泛型变换实战
package com.example.myapplication.kotlinlearn06

class kt104<T>(val isMap: Boolean, val inputType: T) {
    //false,返回null
    //true ,返回调用者本身
    inline fun <R> map(mapAction: (T) -> R): R? = mapAction(inputType).takeIf { isMap }
}

//TODO 104.Kotlin的泛型变换实战;’

fun main() {
    val p1: kt104<Int> = kt104(isMap = true, inputType = 333)
    val r: String? = p1.map {
        "aaa"
    }
    println("变换后的结果是$r")
}
  • kotlin泛型类的约束
    T:Person 这样写的话只有Person 以及Person的子类才可以传进去。

  • Kotlin抽象类

package com.example.myapplication.kotlinlearn06

abstract class BaseActivity {
    fun onCreate() {
        setContentView(getLayoutID())
        initView()
        initData()
        initXXX()
    }

    private fun setContentView(layoutID: Int) = println("你好啦啦啦")

    abstract fun getLayoutID(): Int
    abstract fun initView()
    abstract fun initData()
    abstract fun initXXX()

}

class MainActivity : BaseActivity() {
    override fun getLayoutID(): Int {
        return 1223
    }

    override fun initView() {

    }

    override fun initData() {
    }

    override fun initXXX() {
    }

    fun show() = super.onCreate()

}

//TODO 101-Kotlin的抽象类详解
fun main() = MainActivity().show()
  • kotlin中vararg关键字
package com.example.myapplication.kotlinlearn06

class kt106<T>(vararg objects: T, var isMap: Boolean) {
    //out 我们的T只能被读取,不能被修改
    private val objectArray: Array<out T> = objects

    fun showObj(index: Int): T? = objectArray[index].takeIf { isMap }
}

//TODO 106.kotlin的vararg关键字(动态参数)
fun main() {
    val p = kt106("aaa", "ddd", isMap = true)
    println(p.showObj(0))
    println(p.showObj(1))
    println(p.showObj(2))
}
  • Kotlin的[]操作符
package com.example.myapplication.kotlinlearn06

class kt107<T>(vararg objects: T, var isMap: Boolean) {
    //out 我们的T只能被读取,不能被修改
    private val objectArray: Array<out T> = objects

    fun showObj(index: Int): T? = objectArray[index].takeIf { isMap }

    //运算符重载
    operator fun get(index: Int): T? = objectArray[index].takeIf { isMap }
}

//TODO 107.Kotlin的[]操作符讲解
fun main() {
    val p = kt107("aaa", "ddd", isMap = true)
    p[0]
    println(p[1])
}

6.1协变 逆变

  • 协变讲解
package com.example.myapplication.kotlinlearn06

interface Producer<out T> {//out T 代表此泛型在整个生产者里边 这个T只能被读取,不能被修改了

    fun getT(): T

}

interface Consumer<in T> {
    //消费者 ,只能修改 不能被读取
    fun consumer(item: T) //只能被修改

}

//TODO 108.协变讲解-KT
fun main() {
    //TODO 协变  相当于Java里的? extends Person  这样保证了只能接受 Person以及Person的子类

}
  • 协变讲解
package com.example.myapplication.kotlinlearn06

interface Producer<out T> {//out T 代表此泛型在整个生产者里边 这个T只能被读取,不能被修改了

    fun getT(): T

}

interface Consumer<in T> {
    //消费者 ,只能修改 不能被读取
    fun consumer(item: T) //只能被修改

}

//TODO 108.协变讲解-KT
fun main() {
    //TODO 协变  相当于Java里的? extends Person  这样保证了只能接受 Person以及Person的子类
    //  协变 可以在使用处协变 也可以在生命处协变【Java只有在使用处协变】
    // 逆变  子类去接收父类 in T 相当于Java 里的 ? super Person 这样保证了 能接收Person以及 Person的父类

    // 总结: 协变:out 父类 = 子类
    //   逆变: in  子类=父类
}
  • Kotlin中使用in 和out
package com.example.myapplication.kotlinlearn06

class kt110 {
}

// 小结,当我们对整个类里边的泛型,只能修改,不能读取时,可以声明为逆变
//  当我们对泛型,只能读取,不能给外界修改更新时,可以声明为协变
class SetClass<out T>(item: T) { //声明式逆变泛型,Java不能在声明处,只能在使用处
    // 200个函数,对T只能修改,不能对外界读取
    val res = item
    fun get(): T {
        return res
    }

}

// TODO 110-Kotlin中使用in和out
fun main() {
    val list: List<Int> //不可变
    val list2: MutableList<Int> //可变集合

}


  • reified关键字 监测 泛型T的类型
package com.example.myapplication.kotlinlearn06

class Object1

inline fun <reified T> showTypeInfo(item: T) {
    if (Object1() is T) {
        println("aa")
    } else if (item is Object1) {

    }
    val list = listOf("aa", "bb")
    list.shuffled().first()//随机获取集合中的元素

}

class kt111 {
}

//TODO reified 是真泛型类型的监测
fun main() {

}
  • Kotlin 的 扩展函数
package com.example.myapplication.kotlinlearn06

class Object1

inline fun <reified T> showTypeInfo(item: T) {
    if (Object1() is T) {
        println("aa")
    } else if (item is Object1) {

    }
    val list = listOf("aa", "bb")
    list.shuffled().first()//随机获取集合中的元素

}

class kt111 {
}

//TODO reified 是真泛型类型的监测
fun main() {

}
  • 超类上定义扩展函数
package com.example.myapplication.kotlinlearn06

private fun Any.showPrintlnContent() = println("当前的内容是$this") //将方法私有化,this永远是调用者本身

//TODO kt113-超类上定义扩展函数
fun main() {
    true.showPrintlnContent()
}
  • Kotlin泛型的扩展函数
package com.example.myapplication.kotlinlearn06

//TODO 114.Kotlin的泛型扩展函数
fun <T> T.showContentInfo() =
    println("${if (this is String) "你的字符串长度是$length" else "你不是字符串,你的内容是$this"}")


fun main() {
    "许远志".showContentInfo()
    true.showContentInfo()
}
  • Kotlin的标准函数与泛型扩展函数
package com.example.myapplication.kotlinlearn06

//TODO 115.Kotlin的标准函数与泛型扩展函数

fun main() {
    "string".mLet {
        true
        "aa"
    }
}

private inline fun <I, O> I.mLet(lambda: (I) -> O): O = lambda(this)
  • Kotlin的内置函数与扩展属性
package com.example.myapplication.kotlinlearn06

class kt116

//扩展属性
val String.myInfo: String
    get() = "许远志"

fun String.showPrintln(): String {
    println("aaa")
    return this
}

//TODO 116.Kotlin内置函数与扩展属性
fun main() {
    // run 和let会根据最后一行的返回值作为返回值
    // run 持有this let 持有it
    //TODO 扩展属性
    println("this".myInfo)
    "333".showPrintln().myInfo

}
  • Kotlin可空类型扩展函数
package com.example.myapplication.kotlinlearn06

class kt116

//扩展属性
val String.myInfo: String
    get() = "许远志"

fun String.showPrintln(): String {
    println("aaa")
    return this
}

//TODO 116.Kotlin内置函数与扩展属性
fun main() {
    // run 和let会根据最后一行的返回值作为返回值
    // run 持有this let 持有it
    //TODO 扩展属性
    println("this".myInfo)
    "333".showPrintln().myInfo

}
  • infix中缀表达式
package com.example.myapplication.kotlinlearn06

//TODO 118.Kotlin的infix关键字
//自定义的中级表达式+扩展函数一起使用
// infix  中缀表达式是简化我们的代码
private infix fun <C1, C2> C1.go(c2: C2) {

}

fun main() {
    123.go("许远志")
    123 go "许远志"
}
  • 导入扩展文件
package com.example.myapplication.kotlinlearn06
//导入扩展文件
import com.example.myapplication.kotlinlearn06.randomItemValue

//TODO 119.Kotlin的定义扩展文件

fun main() {
    val list: List<String> = listOf("张三", "李四", "王五")
    //第一种不使用扩展文件
    println(list.shuffled().first())


    println(list.randomItemValue())

}
package com.example.myapplication.kotlinlearn06

fun <E> Iterable<E>.randomItemValue() = shuffled().first()
  • 重命名扩展函数
package com.example.myapplication.kotlinlearn06

//导入扩展文件
import com.example.myapplication.kotlinlearn06.randomItemValue as p

//TODO 119.Kotlin的定义扩展文件

fun main() {
    val list: List<String> = listOf("张三", "李四", "王五")
    //第一种不使用扩展文件
    println(list.shuffled().first())


    println(list.p())

}

7. 手写内置函数

  • 手写apply函数
package com.example.myapplication.kotlinlearn06

class kt121 {

}

fun main() {
    "许远志".mApply {
        "aaa"
    }.apply { }
}

/*
  private 表示私有
  inline 因为我们的函数是高阶函数,需要使用内联对lambda进行优化处理
  fun<INPUT> 函数中声明一个泛型
  INPUT.mApply 表示所有的类型都能调用这个函数,
  INPUT.()代表对这个泛型进行了匿名函数扩展 ,函数扩展持有的this,this持有的调用者本身
  Unit 永远返回调用者本身
  lambda(this)  永远都有this  ,this可以省略
 */
private inline fun <INPUT> INPUT.mApply(lambda: INPUT.() -> Unit): INPUT {
    lambda()
    return this;
}
  • DSL学习
package com.example.myapplication.kotlinlearn06

import java.io.File

//TODO 122.Kotlin的DSL学习
// TODO dsl学习  就是领域专用语言(Domain  Specified Language/DSL)  Gradle,Json,XML等

inline fun File.applyFile(action: (String, String) -> Unit): File {
    action(name, this.name)
    return this
}

fun main() {

}
  • Kotlin的map变换函数
package com.example.myapplication.kotlinlearn06

class kt123 {
}

//TODO 123.Kotlin的map变换函数
fun main() {
    var list: MutableList<String> = mutableListOf("张三", "李四", "王五")
    //原理:及时吧匿名函数最后一个返回值加入到新的集合里面去,
    var list2 = list.map {
        //it 等于 每一个元素 ”张三" "李四" "王五"
        "it 是$it"
        "$it"
    }.map {
        "$ it的长度是${it.length}"
    }
    println(list2)
}
  • 变换函数flatmap
package com.example.myapplication.kotlinlearn06

class kt124 {
}

//TODO 124.Kotlin的变换函数flatMap
fun main() {
    val list: List<String> = mutableListOf("张三", "李四", "王五")
    val list2 = list.flatMap { //每次都会返回一个集合 ,把买一个集合加到新集合里
        listOf("aaa", "bbb", "ccc")  //会做扁平化处理 ,把每个元素变成一个新的集合,然后又加入到新的集合去
    }
    val list3 = list.map {
        "赵六"
    }
    println(list2)
    println(list3)
}
  • 过滤函数filter
package com.example.myapplication.kotlinlearn06

class kt125 {
}

//TODO 125.过滤函数 filter
fun main() {
    val names = listOf("张三", "李四", "王五")
    val result = names.filter {
        it == "张三"   //如果为true 会加入到新的集合 如果为false 则过滤掉
    }
    names.filter {
        it.contains('张')
    }.map {
        println("$it")
    }
    println(result) //新集合 把过滤后的元素加入新集合
}
  • 合并函数zip
package com.example.myapplication.kotlinlearn06

class kt126 {
}

//TODO 126.Kotlin的合并函数zip
fun main() {
    val names = listOf("张三", "李四", "王五")
    val ages = listOf(1, 2, 3)

    val zip: List<Pair<String, Int>> = names.zip(ages)
    println(zip.toMap())
    println(zip)
    //遍历
    zip.forEach {
        //
        println("姓名是${it.first},年龄是${it.second}")
    }
    //解构
    zip.toMap().forEach { (k, v) ->
        println("k是$k,v是$v")

    }
}
  • 函数式编程(响应式编程)
package com.example.myapplication.kotlinlearn06

class kt126 {
}

//TODO 126.Kotlin的合并函数zip
fun main() {
    val names = listOf("张三", "李四", "王五")
    val ages = listOf(1, 2, 3)

    val zip: List<Pair<String, Int>> = names.zip(ages)
    println(zip.toMap())
    println(zip)
    //遍历
    zip.forEach {
        //
        println("姓名是${it.first},年龄是${it.second}")
    }
    //解构
    zip.toMap().forEach { (k, v) ->
        println("k是$k,v是$v")

    }
}
  • Kotlin的互操作性和可空性
package com.example.myapplication.kotlinlearn06

//TODO 128.Kotlin的互操作性与可空性
fun main() {
    var name: String? = "a"//接收Java的变量的时候要用string?来接收Java的值
    name = null

    println(name?.length)
}

7.1 Kotlin的单例模式

package com.example.myapplication.kotlinlearn06

//TODO 单例模式
//1.饿汉式的实现 KT版本   先把实例实例化出来
object Singleton

//2. 懒汉式实现
class Singleton2 private constructor() {
    companion object {
        private var instance: Singleton2? = null
            get() {
                if (field == null) {
                    field = Singleton2()
                }
                return field
            }

        fun getInstance(): Singleton2? = instance
    }
}

// 3.线程安全版本
class Singleton3 private constructor() {
    companion object {
        private var instance: Singleton3? = null
            get() {
                if (field == null) {
                    field = Singleton3()
                }
                return field
            }

        @Synchronized
        fun getInstance(): Singleton3? = instance
    }
}

//4. 双重校验锁版本
class Singleton4 private constructor() {
    companion object {
        val instance: Singleton4 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) { Singleton4() }
    }
}


7.2 Kotlin的注解

  • @JvmName
@file:JvmName("Stu") //在编译时把类名改成自定义的名称
package com.example.myapplication.kotlinlearn06

class kt130 {
}

//TODO 130.注解@jvmName
fun main() {
    println("hello world")
}
  • JvmField注解
package com.example.myapplication.kotlinlearn06

class kt131 {
    @JvmField //把反编译后的Java代码修饰符变成public
    val names = listOf("张三", "李四", "王五")
}

// TODO 131.注解@JvmField
fun main() {

}
  • JvmStatic注解
package com.example.myapplication.kotlinlearn06

class MyObject {
    companion object {
        @JvmField
        val TARGET = "张三"

        @JvmStatic //加上这个注解之后,在Java里使用这个方法就可以直接用了,
        fun showAction(name: String) = println("$name 要去 $TARGET 玩")
    }
}

//TODO 133.注解@JvmStatic与Kotlin的关系
fun main() {
    //KT 端
    println(MyObject.TARGET)
    MyObject.showAction("啦啦啦")
}

7.3 手写RxJava

package com.example.myapplication.kotlinlearn06

class kt134 {
}

// TODO 134.手写RxJava操作符
//  Lambda是以最后一行作为返回值
fun main() {
    create {
        "333"
    }.map {
        "张三"
        true
        "ddd"
    }.map {

    }
}


class RxJavaCoreClassObject<T>(val valueItem: T)

inline fun <INPUT, OUTPUT> RxJavaCoreClassObject<INPUT>.map(mapAction: INPUT.() -> OUTPUT): RxJavaCoreClassObject<OUTPUT> {
    val mapResult = valueItem.mapAction()
    return RxJavaCoreClassObject(mapResult)
}

//create 接收一个lambda表达式作为参数,然后执行lambda的函数体,然后等create参数调用
inline fun <CREATE_OUTPUT> create(createLambda: () -> CREATE_OUTPUT): RxJavaCoreClassObject<CREATE_OUTPUT> {
    val createResult: CREATE_OUTPUT = createLambda()
    return RxJavaCoreClassObject(createResult)
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/549064.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

更改ip地址的几种方式有哪些

在数字化时代&#xff0c;IP地址作为网络设备的标识&#xff0c;对于我们在网络世界中的活动至关重要。然而&#xff0c;出于多种原因&#xff0c;如保护隐私、访问特定网站或进行网络测试&#xff0c;我们可能需要更改IP地址。虎观代理将详细介绍IP地址的更改方法与步骤&#…

纯golang开发的mqtt server

Mochi-MQTT Server github地址&#xff1a;https://github.com/mochi-mqtt/server Mochi-MQTT 是一个完全兼容的、可嵌入的高性能 Go MQTT v5&#xff08;以及 v3.1.1&#xff09;中间件/服务器。 Mochi MQTT 是一个完全兼容 MQTT v5 的可嵌入的中间件/服务器&#xff0c;完…

使用colab进行yolov5小demo练习

输入一张动物的图片进行目标检测和分类 !pip install yolov5 import torch from PIL import Image from torchvision import transforms from yolov5.models.experimental import attempt_load from yolov5.utils.general import non_max_suppression# 加载YOLOv5模型 device …

PLC远程通信:实现工业自动化的关键技术

在当今高度信息化和自动化的时代&#xff0c;工业领域对于实时数据的准确传输和迅速响应提出了更高要求。而PLC(可编程逻辑控制器)远程通信技术&#xff0c;正是能够实现工业自动化的关键技术之一。 首先&#xff0c;我们需要了解PLC远程通信的原理。PLC作为一种专用计算机控制…

【HormonyOS4+NEXT】TypeScript基础语法详解

&#x1f64b;‍ 一日之际在于晨 ⭐本期内容&#xff1a;TypeScript基础语法详解 &#x1f3c6;系列专栏&#xff1a;鸿蒙HarmonyOS4NEXT&#xff1a;探索未来智能生态新纪元 文章目录 前言变量与类型函数类与接口类&#xff08;Class&#xff09;接口&#xff08;Interface&am…

SD-WAN企业组网:多样化的应用场景

随着企业网络环境的快速发展&#xff0c;SD-WAN技术正成为实现站点间网络互通的关键所在。它不仅支持企业站点对因特网、SaaS云应用和公有云等多种业务的高效访问&#xff0c;更能满足多样化的业务需求。深入探讨SD-WAN的组网应用场景&#xff0c;我们能够发现其广泛的适用性和…

免费打造个人专属的高颜值本地大模型AI助手,无限量使用 Ollama+LobeChat开源工具,在本地运行AI大模型,安全的和AI对话。

文章目录 1、安装ollama2、下载模型3、安装lobechat4、卸载Ollama 1、安装ollama 第一步&#xff0c;首先安装ollama&#xff0c;选择对应系统的安装包 ollama官网地址&#xff1a;https://ollama.com/ 本问是lunix系统上安装ollama&#xff1a; curl -fsSL https://ollama.…

Python对txt文本文件内容进行替换,以便通过Origin进行数据分析

因为要使用Origin进行数据分析&#xff0c;数据集为单行文本逗号隔开&#xff0c;无法直接复制粘贴到Origin中&#xff0c;故为此整理了一下代码&#xff0c;方便后续直接使用。 一、任务需求 有个1.txt文档文件里面是一行数据信息&#xff0c;要将其规整为每行一个数据&…

排序:冒泡排序,直接插入排序,简单选择排序,希尔排序,快速排序,堆排序,二路归并排序

目录 一.冒泡排序 代码如下 冒泡排序时间复杂度分析 二.直接插入排序 直接插入排序时间复杂度分析 直接插入排序优化&#xff1a;折半插入排序 三.简单选择排序 简单选择排序优化&#xff1a;双向选择排序 选择排序时间复杂度 双向选择排序时间复杂度 四.希尔排序 希…

Java反序列化基础-类的动态加载

类加载器&双亲委派 什么是类加载器 类加载器是一个负责加载器类的对象&#xff0c;用于实现类加载的过程中的加载这一步。每个Java类都有一个引用指向加载它的ClassLoader。而数组类是由JVM直接生成的&#xff08;数组类没有对应的二进制字节流&#xff09; 类加载器有哪…

贝锐蒲公英企业路由器X5 Pro:无需专线和IT人员,分钟级异地组网

尽管我们公司规模较小&#xff0c;只有十几个人&#xff0c;但为了确保项目资料的安全&#xff0c;依旧在公司内部自建了文件存储服务器和办公系统。 但是&#xff0c;随着项目数量的增加&#xff0c;大家出差办公的情况也愈发普遍&#xff0c;如何解决远程访问内部系统成了问…

公司聚会计划:最优宾客名单的算法设计与分析

公司聚会计划&#xff1a;最优宾客名单的算法设计与分析 问题描述算法设计C代码实现时间复杂度分析空间复杂度分析结论 在组织公司聚会时&#xff0c;一个重要的考虑因素是如何确保聚会的愉快氛围。在本问题中&#xff0c;公司主席希望在聚会上避免员工及其直接主管同时出席&am…

Python写FTP文件自动传输脚本

FTP&#xff08;File Transfer Protocol&#xff09;是一种用于文件传输的标准协议&#xff0c;当我们需要上传或下载文件时&#xff0c;经常会使用 FTP。如果每天需要上传或下载大量文件&#xff0c;手工操作无疑是一件费时费力的事情。在本篇文章中&#xff0c;我们将向您介绍…

中国建筑模板出口供应商

随着"一带一路"倡议的深入推进,中国基建企业"走出去"的步伐正在加快。与之相应,建筑模板产品作为工程建设的重要材料,其国际化供应也愈发受到重视。在众多建筑模板生产企业中,贵港市能强优品木业有限公司以其卓越的产品质量和丰富的出口经验,成为了国内知名…

sed 字符替换时目标内容包含 特殊字符怎么处理

背景 想写一个自动修改配置的脚本&#xff0c;输入一个 mysql jdbc 的连接路径&#xff0c;然后替换目标配置中的模版内容&#xff0c;明明很简单的一个内容&#xff0c;结果卡在了 & 这个符号上。 & 到底是什么特殊字符呢&#xff1f;结论&#xff1a;它代表要替换的…

GmSSL-3.1.1编译

1.源码下载&#xff1a; 下载地址&#xff1a;https://github.com/guanzhi/GmSSL/releases选择对应版本下载。 ​ 2.选择要下载的源码包&#xff1a; ​ 2.编译&#xff1a; 2.1 windows编译&#xff1a;打开vs命令行&#xff0c;选择想要编译的版本&#xff0c;x86或x64…

大数据、数据架构、推荐冷启动...小红书的 AI 数据新方案都在这个会

伴随着行业数据持续积累&#xff0c;人工智能正加速渗透各类场景&#xff0c;大数据、数据架构和推荐系统等领域&#xff0c;依然是各行各业目之所聚。4 月 19 至 20 日&#xff0c;「DataFunCon 2024 上海站」来袭&#xff01;大会以“数聚垂域&#xff0c;智领未来”为主题…

数据结构——栈(C++实现)

数据结构——栈 什么是栈栈的实现顺序栈的实现链栈的实现 今天我们来看一个新的数据结构——栈。 什么是栈 栈是一种基础且重要的数据结构&#xff0c;它在计算机科学和编程中扮演着核心角色。栈的名称源于现实生活中的概念&#xff0c;如一叠书或一摞盘子&#xff0c;新添加…

AI概念普及-LangChain

文章目录 概念产品架构核心特性核心组件使用场景其他资源开发支持结论Langchain详细介绍LangChain的具体实现原理LangChain如何与其他大型语言模型&#xff08;LLM&#xff09;集成&#xff0c;有哪些具体的接口或协议&#xff1f;LangChain的性能表现和优化策略有哪些&#xf…

由于找不到msvcr120.dll,无法继续执行代码的详细处理方法,教你快修复msvcr120.dll

DLL文件&#xff0c;全称动态链接库文件&#xff0c;在计算机系统中具有重要作用。其中&#xff0c;msvcr120.dll是一个常见的DLL文件&#xff0c;它关联了许多程序和应用的正常运行。本指南将深入解释 msvcr120.dll文件的功能&#xff0c;并阐述如果缺少该文件会引起什么样的问…