美文网首页
Kotlin知识总结:

Kotlin知识总结:

作者: 因为我的心 | 来源:发表于2023-02-03 23:44 被阅读0次

1、Kotlin是静态语言还是动态语言?

答:是静态语言,在编译器判断;


图片.png

2、Kotlin类和Java区别:

Kotlin的函数可以写到类里面,也可以写到外面;
Java的方法只能写到类里面;

3、Kotlin编译时常量只能在函数之外定义,为什么?

编译时常量只能在函数之外定定义,就可以在编译期间初始化了(如果在函数之内定义,就必须在运行时才能调用函数赋值,何来编译时常量一说)

4、Kotlin语言只有一种数据类型

看起来都是引用类型,实际上编译器会在java字节码中,修改为"基本类型"

5、Kotlin函数类型隐式返回(也就是lambda函数)

//--------------第一种写法----------------
//第一步:函数输入输出的声明
val methodAction:() -> String
//第二步:对上面函数的实现
methodAction = {
   "哈哈哈"//匿名函数不要写return,最后一行就是返回值
}
//第三步:调用此函数
println(methodAction())
//--------------第二种写法----------------
val methodAction :(Int,Int,Int) ->String ={number1,number2,number3 ->
"$number1,$number2,$number3,"
}
 methodAction.invoke(1,2,3)
 methodAction(1,2,3)
val methodAction2: (String) - >String = {"$it"}
//--------------第三种写法----------------
val methodAction3 ={number1,number2,number3 ->
"$number1,$number2,$number3,"
}
 methodAction3(1,2,3)

//--------------代替接口返回写法----------------
fun login(name:String,pwd:String,result:(String,Int)->Unit){
   result("登录成功",200)
}
//--------------第四种写法----------------
//方式一:
loginAPI("luo","123456"){ msg:String,code:Int ->
}
//方式二:
loginAPI("luo","123456",result = { msg:String,code:Int ->
})
//方式三:
loginAPI("luo","123456"){ msg:String,code:Int ->
}
//被调用的方法
fun loginAPI(name:String,pwd:String,result:(String,Int)->Unit){
   result("登录成功",200)
}

6、内联函数

1、Kotlin函数使用lambda作为参数,就需要声明成内联;
2、lambda如果此函数,不使用内联。在调用端,会生成多个对象来完成lambda的调用(会造成性能损耗)->可以查看Kotlin编译的字节码;
3、如果此函数,使用内联,相当于C++ #define 宏定义 宏替换;会把代码替换到调用处,调用处没有任何函数的开辟,对象的开辟 的损耗;

总结:如果函数参数有lambda,尽量使用 inline 关键字,这样内部会做优化,减少函数开辟 对象开辟的性能损耗。

//内联函数
inline fun loginAPI(name:String,pwd:String,result:(String,Int)->Unit){
   result("登录成功",200)
}

7、Kotlin 的函数引用学习

// TODO 32.Kotlin语言的函数引用学习
fun main() {
    // 函数引用
    // lambda属于函数类型的对象,需要把methodResponseResult普通函数变成 函数类型的对象(函数引用)

    // login("Derry2", "123456", ::methodResponseResult)

    val obj = ::methodResponseResult
    val obj2 = obj
    val obj3 =  obj2

    login("Derry", "123456", obj3)
}

fun methodResponseResult(msg: String, code: Int) {
    println("最终登录的成果是:msg:$msg, code:$code")
}


// 模拟:数据库SQLServer
const val USER_NAME_SAVE_DB4 = "Derry"
const val USER_PWD_SAVE_DB4= "123456"

inline fun login(name: String, pwd: String, responseResult: (String, Int) -> Unit) {
    if (USER_NAME_SAVE_DB4 == name && USER_PWD_SAVE_DB4 == pwd) {
        // 登录成功
        // 做很多的事情 校验成功信息等
        responseResult("登录成功", 200)
        // ...
    } else {
        // 登录失败
        // 做很多的事情 登录失败的逻辑处理
        // ...
        responseResult("登录失败错了", 444)
    }
}

8、Kotlin 返回一个函数

package com.derry.s2

// TODO 33.Kotlin语言的函数类型作为返回类型
fun main() {
    val r = show("学习KT语言")
    // r 是show函数的 返回值

    val niming_showMethod = showMethod("show")
    // niming_showMethod 是 showMethod函数的返回值 只不过这个返回值 是一个 函数

    // niming_showMethod == 匿名函数
    println(niming_showMethod("Derry", 33))
}

fun show(info: String): Boolean {
    println("我是show函数 info:$info")
    return true
}

fun show2(info: String): String {
    println("我是show函数 info:$info")
    return "DDD"
}

fun show3(info: String): String {
    println("我是show函数 info:$info")
    return /*888*/ ""
}

// showMethod函数 再返回一个 匿名函数
fun showMethod(info: String): (String, Int) -> String {
    println("我是show函数 info:$info")

    // return 一个函数 匿名函数
    return { name: String, age: Int ->
        "我就是匿名函数:我的name:$name, age:$age"
    }
}

9、Kotlin语言的匿名函数与具名函数

Kotlin版:
// TODO 34.Kotlin语言的匿名函数与具名函数
fun main() {

    // 匿名函数
    showPersonInfo("lisi", 99, '男', "学习KT语言") {
        println("显示结果:$it")
    }

    // 具名函数 showResultImpl
    showPersonInfo("wangwu", 89, '女', "学习C++语言", ::showResultImpl)

}

fun showResultImpl(result: String) {
    println("显示结果:$result")
}

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)
}
Java版:
package com.derry.s2;

interface IShowResult { // 接口的折中方案 解决 kt的lambda问题
    void result(String result);
}

// TODO 34.Kotlin语言的匿名函数与具名函数
public class KtBase34 {

    public static void main(String[] args) { // psv
        // 匿名函数 - 匿名接口实现
        showPersonInfo("lisi", 99, 'm', "study cpp", new IShowResult() {
            @Override
            public void result(String result) {
                System.out.println("显示结果:" + result);
            }
        });

        // 具名函数 - 具名接口实现 showResultImpl
        IShowResult showResultImpl = new MshowResultImpl();
        showPersonInfo("wangwu", 88, 'n', "study kt", showResultImpl);
    }

   static class MshowResultImpl implements IShowResult {

        @Override
        public void result(String result) {
            System.out.println("显示结果:" + result);
        }
    }

    static void showPersonInfo(String name, int age, char sex, String study, IShowResult iShowResult) {
        String str = String.format("name:%s, age:%d, sex:%c, study:%s", name, age, sex, study);
        iShowResult.result(str);
    }
}

10、Kotlin 空合并操作符

//如果info等于null,打印 ?: 后面的值
var info = null
println(info?:"是null啊")
//let 函数+空合并操作符
println(info?.let{ $it}?:"是null啊")

11、kotlin 中==和===区别:

//== 值或者内容的比较,相当于java的equals
//=== 引用的比较 

12、Kotlin语言中Double转Int与类型格式化:

fun main() {
    println(65.4645654.toInt()) // 65 四舍五入

    println(65.4645654.roundToInt())  // 65 四舍五入

    println(65.8343433.roundToInt()) // 66 四舍五入

    // 结论:用 roundToInt()函数,保证 Double ->转Int 持有四舍五入的效果

    // r的类型: String,保留3位小数
    val r  = "%.3f".format(65.8343433)
    println(r)

}

13、Kotlin语言的apply内置函数

示例: info.apply
1、apply函数返回类型,用于info本身;
2、apply函数的匿名函数里面持有的是this == info本身;

   // info.apply特点:apply函数始终是返回 “info本身”,所以可以链式调用
   var info = "xiaoming"
    info?.apply {
        println("长度是:$length")
    }.apply {
        println("最后一个字符是:${this[length -1]}")
        true
    }.apply {
        println("全部转成小写是:${toLowerCase()}")
    }

14、Kotlin语言的let内置函数

示例:value.let
1、let函数返回类型,是根据匿名函数最后一行的变化而变化;
2、let函数的匿名函数里面持有的是it == 集合本身;

// let方式 对集合第一个元素相加
 val result2 = listOf(6, 5, 2, 3, 5, 7).let {
        // it == list集合
        it.first() + it.first() 
    }
    println(result2)
// let方式 + 空合并操作符 对值判null,并返回 简化版本
fun getMethod4(value: String?) =
     value?.let {
        "欢迎回来${it}非常欢迎"
    } ?: "你传递的内容是null,你在搞什么飞机"

15、Kotlin语言的run内置函数

str.run
1、run函数返回类型,是根据匿名函数最后一行的变化而变化;
2、run函数的 匿名函数里面持有的是this == str 本身;

fun main() {
    val str = "Derry is OK"
    val r1 : Float = str.run {
        // this == str本身
        true
        5435.5f
    }
    println(r1)
    // 下面是 具名函数 配合 run函数
    // 2.具名函数判断长度 isLong
    // 这个是属于 匿名函数 配合 run
    str.run {
        // this == str本身
    }
    // 这个是属于具名函数
    // str.run(具名函数)
    str
        .run(::isLong) // this == str本身
        .run(::showText) // this == isLong返回的boolean值
        .run(::mapText)
        .run(::println)

    println()


    // >>>>>>>>>>>>>>>>>>>>>> 上面全部都是具名函数调用给run执行  下面全部是 匿名函数调用给run执行
    str
        .run {
            if (length > 5) true else false
        }
        .run {
            if (this) "你的字符串合格" else "你的字符串不合格"
        }
        .run {
            "【$this】"
        }
        .run {
            println(this)
        }
}

fun isLong(str: String) /* : Boolean */ = if (str.length > 5) true else false
fun showText(isLong: Boolean) /*: String */ = if (isLong) "你的字符串合格" else "你的字符串不合格"
fun mapText(getShow: String) /*: String */ = "【$getShow】"

16、Kotlin语言的with内置函数

with(str) 和run 一样,只是调用方式不同
1、with函数返回类型,是根据匿名函数最后一行的变化而变化;
2、with函数的 匿名函数里面持有的是this == str 本身;

fun main() {
    val str = "李元霸"

    // 具名操作
    /*with(str) {
        this == str本身
    }*/
    val r1 = with(str, ::getStrLen)
    val r2 = with(r1, ::getLenInfo)
    val r3 = with(r2, ::getInfoMap)
    with(r3, ::show)

    println()

    // 匿名操作
    with(with(with(with(str) {
        length
    }) {
        "你的字符串长度是:$this"
    }){
        "【$this】"
    }){
        println(this)
    }
}

fun getStrLen(str: String) = str.length
fun getLenInfo(len: Int) = "你的字符串长度是:$len"
fun getInfoMap(info: String) = "【$info】"
fun show(content: String) = println(content)

17、Kotlin语言的also内置函数

示例: also.apply
1、also函数返回类型,用于str本身;
2、also函数的匿名函数里面持有的是this == str本身;

  // 真正使用also函数的写法规则如下:
    // str.also特点:also函数始终是返回 “str本身”,所以可以链式调用
    str.also {
        println("str的原始数据是:$it")
    }.also {
        println("str转换小写的效果是:${it.toLowerCase()}")
    }.also {
        println("结束了")
    }

18、Kotlin语言的List创建与元素获取

小结:开发过程中,尽量使用 getOrElse 或 getOrNull,才能体现KT的亮点

// 普通取值方式:    索引
// 防止奔溃取值方式: getOrElse getOrNull
val list = listOf("Derry", "Zhangsan", "Lisi", "Wangwu")
// 我们写KT代码,一定不会再出现,空指针异常,下标越界异常
// 防止奔溃取值方式: getOrElse getOrNull
 println(list.getOrElse(4402) {"你越界了啊"})
// getOrNull + 空合并操作符
println(list.getOrNull(222) ?: "你越界了哦哦")

19、Kotlin语言的可变List集合

// TODO 58.Kotlin语言的可变List集合学习
// 可变的集合
// 不可变集合 to 可变集合
// 可变集合 to 不可变集合
fun main() {
    // 可变的集合
    val list = mutableListOf("Derry", "Zhangsna", "Wangwu")
    // 可变的集合,可以完成可变的操作
    list.add("赵六")
    list.remove("Wangwu")
    println(list)

    // 不可变集合 to 可变集合
    val list2 = listOf(123, 456, 789)
    // 不可以的集合,无法完成可变的操作
    // list2.add
    // list2.remove

    val list3 : MutableList<Int> = list2.toMutableList()
    // 可变的集合,可以完成可变的操作
    list3.add(111)
    list3.remove(123)
    println(list3)

    // 可变集合 to 不可变集合
    val list4: MutableList<Char> = mutableListOf('A', 'B', 'C')
    // 可变的集合,可以完成可变的操作
    list4.add('Z')
    list4.remove('A')
    println(list4)

    val list5: List<Char> = list4.toList()
    // 不可以的集合,无法完成可变的操作
    /*list5.add
    list5.remove*/
}

20、Kotlin语言的mutator函数

// 1.mutator += -= 操作
// 2.removeIf
fun main() {
    // 1.mutator += -= 操作
    val list : MutableList<String> = mutableListOf("Derry", "DerryAll", "DerryStr", "Zhangsan")
    list += "李四" // mutator的特性 +=  -+ 其实背后就是 运算符重载而已
    list += "王五"
    list -= "Derry"
    println(list)

    // 2.removeIf
    // list.removeIf { true } // 如果是true 自动变量整个可变集合,进行一个元素一个元素的删除
    list.removeIf { it.contains("Derr") } // 过滤所有的元素,只要是有 Derr 的元素,就是true 删除
    println(list)
}

21、Kotlin语言的解构语法过滤元素学习

// 1.集合配合解构语法
// 2.反编译看Java给三个变量赋值的代码
// 3.解构屏蔽接收值
fun main() {
    val list: List<String> = listOf("李元霸", "李小龙", "李连杰")

    val(value1, value2, value3) = list
    // value1 = ""  val只读的
    println("value1:$value1, value2:$value2, value3:$value3")

    var(v1, v2, v3) = list
    // v1 = "OK"
    println("v1:$v1, v2:$v2, v3:$v3")

    // 用_内部可以不接收赋值,可以节约一点性能
    val(_ , n2, n3) = list
    // println(_) _不是变量名,是用来过滤解构赋值的,不接收赋值给我
    println("n2:$n2, n3:$n3")
}

22、Kotlin语言的Set创建与元素获取

// 1.set 定义 不允许重复
// 2.普通方式elementAt 会越界奔溃
// 3.elementAtOrElse elementAtOrNull
fun main() {
    val set: Set<String> = setOf("lisi", "wangwu", "zhaoliu", "zhaoliu") // set集合不会出现重复元素的
    println(set)
    // set[0] 没有这样 [] 的功能 去Set集合元素
    println(set.elementAt(0)) // [0]
    println(set.elementAt(1))
    println(set.elementAt(2))
    // println(set.elementAt(3)) // [3] 奔溃 会越界
    // println(set.elementAt(4)) // [4] 奔溃 会越界

    println()

    // 使用 list 或 set 集合,尽量使用  此方式,防止越界奔溃异常
    println(set.elementAtOrElse(0) {"越界了"})
    println(set.elementAtOrElse(100) {"越界了了"})

    println(set.elementAtOrNull(0))
    println(set.elementAtOrNull(111))
    // OrNull + 空合并操作符  一起使用
    println(set.elementAtOrNull(88) ?: "你越界啦啊")
}

//Kotlin语言的可变Set集合
fun main() {
   val set : MutableSet<String> = mutableSetOf("李元霸", "李连杰")
    set += "李俊"
    set += "李天"
    set -= "李连杰"
    set.add("刘军")
    set.remove("刘军")
    println(set)
}

23、Kotlin语言的集合转换与快捷函数学习

// 1.定义可变list集合
// 2.List 转 Set 去重
// 3.List 转 Set 转 List 也能去重
// 4.快捷函数去重 distinct
fun main() {
   val list : MutableList<String> = mutableListOf("Derry", "Derry", "Derry", "Leo", "Lance") // list 可以重复元素
    println(list)

    // List 转 Set 去重
    val set /*: Set<String>*/ = list.toSet()
    println(set)

    // List 转 Set 转 List 也能去重
    val list2 /*: List<String>*/ = list.toSet().toList()
    println(list2)

    // 快捷函数去重 distinct
    println(list.distinct()) // 内部做了:先转变成 可变的Set结合  在转换成 List集合
    println(list.toMutableSet().toList()) // 和上面代码等价
}

24、Kotlin语言的Map的创建

fun main() {
    val mMap1 : Map<String, Double> = mapOf<String, Double>("Derry" to(534.4), "Kevin" to 454.5)
    val mMap2 = mapOf(Pair("Derry", 545.4), Pair("Kevin", 664.4))
    // 上面两种方式是等价的哦
}

25、Kotlin语言的读取Map的值

// 方式一 [] 找不到会返回null
// 方式二 getOrDefault
// 方式三 getOrElse
// 方式四 与Java一样 会奔溃
fun main() {
    val mMap /*: Map<String, Int>*/ = mapOf("Derry" to 123,"Kevin" to 654)

    // 方式一 [] 找不到会返回null
    println(mMap["Derry"]) // 背后对[] 运算符重载了
    println(mMap["Kevin"])
    println(mMap.get("Kevin")) // get 与 [] 完完全全等价的
    println(mMap["XXX"]) // map通过key找 如果找不到返回null,不会奔溃

    println()

    // 方式二 getOrDefault
    println(mMap.getOrDefault("Derry", -1))
    println(mMap.getOrDefault("Derry2", -1))

    // 方式三 getOrElse
    println(mMap.getOrElse("Derry") {-1})
    println(mMap.getOrElse("Derry2") {-1})

    println()

    // 方式四 getValue 与Java一样 会奔溃  尽量不要使用此方式
    println(mMap.getValue("Derry"))
    println(mMap.getValue("XXX"))

    // map获取内容,尽量使用 方式二 方式三
}

26、Kotlin语言的遍历Map学习

// 四种方式遍历
fun main() {
    val map /*: Map<String, Int>*/ = mapOf(Pair("Derry", 123), Pair("Kevin", 456), "Leo" to 789)

    // 第一种方式:
    map.forEach {
        // it 内容 每一个元素 (K 和 V)  每一个元素 (K 和 V)  每一个元素 (K 和 V)
        // it 类型  Map.Entry<String, Int>
        println("K:${it.key} V:${it.value}")
    }

    println()

    // 第二种方式:
    map.forEach { key: String, value: Int ->
        // 把默认的it给覆盖了
        println("key:$key, value:$value")
    }

    println()

    // 第三种方式:
    map.forEach { (k /*: String*/, v /*: Int*/) ->
        println("key:$k, value:$v")
    }

    println()

    // 第四种方式:
    for (item /*: Map.Entry<String, Int>*/ in map) {
        // item 内容 每一个元素 (K 和 V)  每一个元素 (K 和 V)  每一个元素 (K 和 V)
        println("key:${item.key} value:${item.value}")
    }
}

27、Kotlin语言的可变Map集合学习

// 1.可变集合的操作 += [] put
// 2.getOrPut 没有的情况
// 3.getOrPut 有的情况
fun main() {
    // 1.可变集合的操作 += [] put
    val map : MutableMap<String, Int> = mutableMapOf(Pair("Derry", 123), "Kevin" to 456, Pair("Dee", 789))
    // 下面是可变操作
    map += "AAA" to(111)
    map += "BBB" to 1234
    map -= "Kevin"
    map["CCC"] = 888
    map.put("DDD", 999) // put 和 [] 等价的

    // 2.getOrPut 没有有的情况
    // 如果整个map集合里面没有 FFF的key 元素,我就帮你先添加到map集合中去,然后再从map集合中获取
    val r: Int = map.getOrPut("FFF") { 555 }
    println(r)
    println(map["FFF"]) // 他已经帮你加入进去了,所以你可以获取

    // 3.getOrPut 有的情况
    val r2 = map.getOrPut("Derry") {666} // 发现Derry的key是有的,那么就直接获取出来, 相当于666备用值就失效了
    println(r2)
}

28、 主构造函数

// 主构造函数:规范来说,都是增加_xxx的方式,临时的输入类型,不能直接用,需要接收下来 成为变量才能用
// _name 等等,都是临时的类型,不能直接要弄,需要转化一下才能用
class KtBase72(_name: String, _sex: Char, _age: Int, _info: String) // 主构造函数
{
    var name = _name
        get() = field // get不允许私有化
        private set(value) {
            field = value
        }

    val sex = _sex
        get() = field
        // set(value) {} 只读的,不能修改的,不能set函数定义

    val age: Int = _age
        get() = field + 1

    val info = _info
        get() = "【${field}】"

    fun show() {
        // println(_name) 临时的输入类型,不能直接用,需要接收下来 成为变量才能用
        println(name)
        println(sex)
        println(age)
        println(info)
    }
}

// TODO 72.Kotlin语言的主构造函数学习
fun main() {
    // KtBase72()

    val p = KtBase72(_name = "Zhangsan", _info = "学习KT语言", _age = 88, _sex = 'M')
    // println(p.name)
    // p.name = "AAA" 被私有化了,不能调用

    p.show()
}
/* 伪代码:

class KtBase73 (_name: String, _sex: Char, _age: Int, _info: String)
{
    var name = _name
    val sex = _sex
    val age = _age
    var info = _info

    fun show() {
        println(name)
    }
}

 */

// var name: String  就相当于  var name = _name  这不过你看不到而已
// 一步到位,不像我们上一篇是分开写的
class KtBase73 (var name: String, val sex: Char, val age: Int, var info: String)
{
    fun show() {
        println(name)
        println(sex)
        println(age)
        println(info)
    }
}

// TODO 73.Kotlin语言的主构造函数里定义属性
fun main() {
    KtBase73(name = "Zhangsan", info = "学习KT语言", age = 88, sex = 'M').show()
}

29、次构造函数

class KtBase74(name: String) // 主构造
{
    // 2个参数的次构造函数,必须要调用主构造函数,否则不通过,  为什么次构造必须调用主构造?答:主构造统一管理 为了更好的初始化设计
    constructor(name: String, sex: Char) : this(name) {
        println("2个参数的次构造函数 name:$name, sex:$sex")
    }

    // 3个参数的次构造函数,必须要调用主构造函数
    constructor(name: String, sex: Char, age: Int) : this(name) {
        println("3个参数的次构造函数 name:$name, sex:$sex, age:$age")
    }

    // 4个参数的次构造函数,必须要调用主构造函数
    constructor(name: String, sex: Char, age: Int, info: String) : this(name) {
        println("4个参数的次构造函数 name:$name, sex:$sex, age:$age, info:$info")
    }
}

// TODO 74.Kotlin语言的次构造函数学习
// name: String, sex: Char, age: Int, info: String
fun main() {
    val p = KtBase74("李元霸") // 调用主构造

    KtBase74("张三", '男') // 调用 2个参数的次构造函数

    KtBase74("张三2", '男', 88) // 调用 3个参数的次构造函数

    KtBase74("张三3", '男', 78, "还在学校新语言") // 调用 4个参数的次构造函数
}

30、构造函数的默认值

class KtBase75(name: String = "李元霸") // 主构造
{
    // 2个参数的次构造函数,必须要调用主构造函数
    constructor(name: String = "李连杰", sex: Char = 'M') : this(name) {
        println("2个参数的次构造函数 name:$name, sex:$sex")
    }

    // 3个参数的次构造函数,必须要调用主构造函数
    constructor(name: String = "李小龙", sex: Char = 'M', age: Int = 33) : this(name) {
        println("3个参数的次构造函数 name:$name, sex:$sex, age:$age")
    }

    // 4个参数的次构造函数,必须要调用主构造函数
    constructor(name: String = "李俊", sex: Char = 'W', age: Int = 87, info: String = "还在学校新开发语言") : this(name) {
        println("4个参数的次构造函数 name:$name, sex:$sex, age:$age, info:$info")
    }
}

// TODO 75.Kotlin语言的构造函数中默认参数学习
fun main() {
    val p = KtBase75("李元霸2") // 调用主构造

    KtBase75("张三", '男') // 调用 2个参数的次构造函数

    KtBase75("张三2", '男', 88) // 调用 3个参数的次构造函数

    KtBase75("张三3", '男', 78, "还在学校新语言") // 调用 4个参数的次构造函数

    KtBase75() // 到底是调用哪一个 构造函数,是次构造 还是 主构造 ? 答:优先调用主构造函数
}

31、lateinit 懒加载

lateinit 是在使用的时候,手动加载的懒加载方式,然后再使用
惰性初始化by lazy 是在使用的时候,自动加载的懒加载方式,然后再使用

class KtBase78 {

    // lateinit val AAA; // AAA 无法后面在修改了,我还怎么延时初始化?
    lateinit var responseResultInfo: String // 我等会儿再来初始化你,我先定义再说,所以没有赋值

    // 模拟服务器加载
    fun loadRequest() { // 延时初始化,属于懒加载,用到你在给你加载
        responseResultInfo = "服务器加载成功,恭喜你"
    }

    fun showResponseResult() {
        // 由于你没有给他初始化,所以只有用到它,就奔溃
        // if (responseResultInfo == null) println()
        // println("responseResultInfo:$responseResultInfo")

        if (::responseResultInfo.isInitialized) {
            println("responseResultInfo:$responseResultInfo")
        } else {
            println("你都没有初始化加载,你是不是忘记加载了")
        }
    }
}

// TODO 78.Kotlin语言的延迟初始化lateinit学习
// 1.lateinit responseResultInfo 定义
// 2.request 懒加载
// 3.showResponseResult
// 4.main 先请求 在显示
fun main() {
    val p = KtBase78()

    // 使用他之前,加载一下(用到它才加载,就属于,懒加载)
    p.loadRequest()

    // 使用他
    p.showResponseResult()
}

32、Kotlin语言的继承与重载的open关键字学习

// KT所有的类,默认是final修饰的,不能被继承,和Java相反
// open:移除final修饰
open class Person(private val name: String) {

    private fun showName() = "父类 的姓名是【$name】"

    // KT所有的函数,默认是final修饰的,不能被重写,和Java相反
    open fun myPrintln() = println(showName())
}

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

    private fun showName() = "子类 的姓名是【${subName}】"

    override fun myPrintln() = println(showName())

}

// TODO 83.Kotlin语言的继承与重载的open关键字学习
// 1.父类 val name  showName()->String  myPrintln->Unit
// 2.子类 myPrintln->Unit
fun main() {
    val person: Person = Student("张三")
    person.myPrintln()
}

33、Kotlin语言的对象声明学习

object KtBase87 {
    /* object 对象类背后做了什么事情

        public static final KtBase87 INSTANCE;

        private KtBase87() {} // 主构造废除一样的效果

        public final void show() {
            String var1 = "我是show函数...";
            ...
            System.out.println(var1);
        }

        // 这个区域是 object 不同点:
        static {
            KtBase87 var0 = new KtBase87();
            INSTANCE = var0;
            String var1 = "KtBase91 init...";
            ...
            System.out.println(var0);
        }

     */

    init {
        println("KtBase91 init...")
    }

    fun show() = println("我是show函数...")
}

fun main() {
    // object KtBase87 既是单例的实例,也是类名
    // 小结:既然是 单例的实例,又是类名,只有一个创建,这就是典型的单例
    println(KtBase87) // 背后代码:println(KtBase87.INSTANCE)
    println(KtBase87) // 背后代码:println(KtBase87.INSTANCE)
    println(KtBase87)
    println(KtBase87)
    println(KtBase87)
    println(KtBase87)

    // 背后代码:KtBase87.INSTANCE.show();
    println(KtBase87.show())
}

34、Kotlin语言的对象表达式学习

interface RunnableKT {
    fun run()
}

open class KtBase88 {

    open fun add(info: String) = println("KtBase88 add:$info")

    open fun del(info: String) = println("KtBase88 del:$info")
}

// TODO  88.Kotlin语言的对象表达式学习
// 1.add del println
// 2.匿名对象表达式方式
// 3.具名实现方式
// 4.对Java的接口 用对象表达式方式
fun main() {
    // 匿名对象 表达式方式
    val p : KtBase88 = object : KtBase88() {

        override fun add(info: String) {
            // super.add(info)
            println("我是匿名对象 add:$info")
        }

        override fun del(info: String) {
            // super.del(info)
            println("我是匿名对象 del:$info")
        }
    }
    p.add("李元霸")
    p.del("李连杰")


    // 具名实现方式
    val p2 = KtBase88Impl()
    p2.add("刘一")
    p2.del("刘二")

    // 对Java的接口 用   KT[对象表达式方式]  方式一
    val p3 = object : Runnable {
        override fun run() {
            println("Runnable run ...")
        }
    }
    p3.run()

    // 对Java的接口 用   Java最简洁的方式 方式二
    val p4 = Runnable {
        println("Runnable run2 ...")
    }
    p4.run()

    // 对KT的接口 用   KT[对象表达式方式]  方式一
    object : RunnableKT {
        override fun run() {
            println("RunnableKT 方式一 run ...")
        }
    }.run()

    // 对KT的接口 用   Java最简洁的方式 方式二
    /*RunnableKT {

    }*/
}

// 小结:Java接口,有两种方式 1(object : 对象表达式)  2简洁版,
//       KT接口,只有一种方式 1(object : 对象表达式)

// 具名实现  具体名字 == KtBase88Impl
class KtBase88Impl : KtBase88() {

    override fun add(info: String) {
        // super.add(info)
        println("我是具名对象 add:$info")
    }

    override fun del(info: String) {
        // super.del(info)
        println("我是具名对象 del:$info")
    }
}

35、Kotlin语言的伴生对象学习

class KtBase89 {

    // 伴生对象
    companion object {
        val info = "DerryINfo"

        fun showInfo() = println("显示:$info")

        val name = "Derry"
    }

    /* companion object {} 背后的逻辑

       private static final String name = "Derry";
       private static final String info = "DerryINfo";
       public static final KtBase89.Companion Companion = new KtBase89.Companion(xxx);

       public static final class Companion {

          @NotNull
          public final String getInfo() {
             return KtBase89.info;
          }

          @NotNull
          public final String getName() {
             return KtBase89.name;
          }

          public final void showInfo() {
             String var1 = "显示:" + ((KtBase89.Companion)this).getInfo();
             boolean var2 = false;
             System.out.println(var1);
          }

          private Companion() {}

          // $FF: synthetic method
          public Companion(DefaultConstructorMarker $constructor_marker) {
             this();
          }
        }

     */
}

// TODO 89.Kotlin语言的伴生对象学习
// 伴生对象的由来: 在KT中是没有Java的这种static静态,伴生很大程度上和Java的这种static静态 差不多的
// 无论 KtBase89() 构建对象多少次,我们的伴生对象,只有一次加载
// 无论 KtBase89.showInfo() 调用多少次,我们的伴生对象,只有一次加载
// 伴生对象只会初始化一次
fun main() {
    // 背后代码:System.out.println(KtBase89.Companion.getInfo())
    println(KtBase89.info)

    // 背后代码:System.out.println(KtBase89.Companion.getName())
    println(KtBase89.name)

    // 背后代码:KtBase89.Companion.showInfo()
    KtBase89.showInfo()

    // new KtBase89();
    KtBase89()
    KtBase89()
    KtBase89()
    KtBase89()
    // ...
}

36、Kotlin语言的嵌套类学习

// TODO 内部类
// 内部类的特点: 内部的类 能访问 外部的类
//              外部的类 能访问 内部的类
class Body(_bodyInfo: String) { // 身体类

    val bodyInfo = _bodyInfo

    fun show() {
        Heart().run()
    }

    // 默认情况下:内部的类 不能访问 外部的类,要增加修饰符inner 成为内部类才可以访问外部类
    inner class Heart { // 心脏类
        fun run() = println("心脏访问身体信息:$bodyInfo")
    }

    inner class Kidney { // 肾脏
        fun work() = println("肾脏访问身体信息:$bodyInfo")
    }

    inner class Hand { // 手
        inner class LeftHand { // 左手
            fun run() = println("左手访问身体信息:$bodyInfo")
        }

        inner class RightHand { // 右手
            fun run() = println("右手访问身体信息:$bodyInfo")
        }
    }
}

// TODO 嵌套类
// 默认情况下:就是嵌套类关系
// 嵌套类特点:外部的类 能访问 内部的嵌套类
//           内部的类 不能访问 外部类的成员
class Outer {

    val info: String  = "OK"

    fun show() {
        Nested().output()
    }

    class Nested {

        fun output() = println("嵌套类")

    }
}

// TODO 90.Kotlin语言的嵌套类学习
fun main() {
    // 内部类:
    Body("isOK").Heart().run()
    Body("isOK").Hand().LeftHand().run()
    Body("isOK").Hand().RightHand().run()

    // 嵌套类:
    Outer.Nested().output()

}

37、.Kotlin语言的数据类学习

数据类使用条件:
条件一:服务器请求回来的响应的 JavaBean LoginResponseBean 基本上可以使用 数据类
条件二:数据类至少必须有一个参数的主构造函数
条件三:数据类必须有参数, var val 的参数
条件四:数据类不能使用 abstract,open,sealed,inner 等等 修饰 (数据类,数据载入的事情 数据存储)
条件五:需求 比较,copy,toString,解构,等等 这些丰富的功能时,也可以使用数据类

// 普通类
class ResponseResultBean1(var msg: String, var code: Int, var data: String) : Any()
// set get 构造函数

// 数据类 -- 一般是用于 JavaBean的形式下,用数据类
data class ResponseResultBean2(var msg: String, var code: Int, var data: String) : Any()
// set get 构造函数 解构操作 copy toString hashCode equals  数据类 生成 更丰富

// TODO 91.Kotlin语言的数据类学习
// 1.普通类 与 数据类 的 toString 背后原理
// 2.前面学习过的 == 与 ===
// 3.普通类的 == 背后原理
// 4.数据类的 == 背后原理
fun main() {
    // val (v1, v2, v3) =list  这个是list集合之前的 解构操作

    println(ResponseResultBean1("loginSuccess", 200, "登录成功的数据..."))
    // 普通类:: Any() toString Windows实现打印了   com.derry.s5.ResponseResultBean1@266474c2

    println(ResponseResultBean2("loginSuccess", 200, "登录成功的数据..."))
    // 数据类:: Any() 默认重写了 父类的 toString  打印子类的toString详情  ResponseResultBean2(msg=loginSuccess, code=200, data=登录成功的数据...)

    println()
    // =====================

    // 前面我们学习  == 值的比较 相当于java的equals      ===引用 对象 比较

    println( // 推理 两个 普通类 的值 是一样的,应该是true ,实际背后并不是这样的
        ResponseResultBean1("loginSuccess", 200, "登录成功的数据...") ==
                ResponseResultBean1("loginSuccess", 200, "登录成功的数据...")
    )
    // Any父类的 equals 实现 (ResponseResultBean1对象引用 比较 ResponseResultBean1对象引用)


    println(
        ResponseResultBean2("loginSuccess", 200, "登录成功的数据...") ==
                ResponseResultBean2("loginSuccess", 200, "登录成功的数据...")
    )
    // Any父类的 equals 被 数据类 重写了 equals 会调用 子类的 equals函数(对值的比较)
}

38、Kotlin语言的copy函数学习

注意事项:使用copy的时候,由于内部代码只处理主构造,所以必须考虑次构造的内容

data class KtBase92 (var name: String, var age: Int) // 主构造
{
    var coreInfo : String = ""

    init {
        println("主构造被调用了")
    }

    // 次构造
    constructor(name: String) : this(name, 99) {
        println("次构造被调用")
        coreInfo = "增加非常核心的内容信息"
    }

    override fun toString(): String {
        return "toString name:$name, age:$age, coreInfo:$coreInfo"
    }
}

/* 生成的toString 为什么只有两个参数?
   答:默认生成的toString 或者 hashCode equals 等等... 主管主构造,不管次构造
    public String toString() {
      return "KtBase92(name=" + this.name + ", age=" + this.age + ")";
    }
 */

// TODO 92.Kotlin语言的copy函数学习
fun main() {
    val p1 = KtBase92("李元霸") // 调用次构造初始化对象
    println(p1)

    val newP2 = p1.copy("李连杰", 78)
    println(newP2)

    // copy toString hashCode equals 等等... 主管主构造,不管次构造
    // 注意事项:使用copy的时候,由于内部代码只处理主构造,所以必须考虑次构造的内容
}

39、Kotlin语言的解构声明学习

// 普通类
class Student1(var name: String , var age: Int, var sex: Char) {

    // 注意事项:component0 顺序必须是 component1 component2 component3 和成员一一对应,顺序下来的
    operator fun component1() = name
    operator fun component2() = age
    operator fun component3() = sex
}

// 数据类
data class Student2Data(var name: String , var age: Int, var sex: Char)

// TODO 93.Kotlin语言的解构声明学习
fun main() {
    val(name, age, sex) = Student1("李四", 89, '男')
    println("普通类 结构后:name:$name, age:$age, sex:$sex")

    val(name1, age1, sex1) = Student2Data("李四", 89, '男')
    println("数据类 结构后:name:$name1, age:$age1, sex:$sex1")

    val(_, age2, _) = Student1("李四", 89, '男')
    println("数据类 结构后: age2:$age2")
}

40、Kotlin语言的枚举类学习

// KT想表达:枚举其实也是一个class,为什么,就是为了 枚举可以有更丰富的功能
enum class Week {
    星期一,
    星期二,
    星期三,
    星期四,
    星期五,
    星期六,
    星期日
}

// TODO 95-Kotlin语言的枚举类学习
fun main() {
    println(Week.星期一)
    println(Week.星期四)

    // 枚举的值 等价于 枚举本身
    println(Week.星期二 is Week)
}

41、Kotlin语言的枚举类定义函数学习

package com.derry.s5

// 四肢信息class,我就是为了方便toString打印
data class LimbsInfo (var limbsInfo: String, var length: Int) {
    fun show() {
        println("${limbsInfo}的长度是:$length")
    }
}

enum class Limbs(private var limbsInfo: LimbsInfo) {
    LEFT_HAND(LimbsInfo("左手", 88)), // 左手
    RIGHT_HAND(LimbsInfo("右手", 88)), // 右手

    LEFT_FOOT(LimbsInfo("左脚", 140)), // 左脚
    RIGHT_FOOT(LimbsInfo("右脚", 140)) // 右脚

    ; // 结束枚举值

    // 1. WEEK 这个时候 再定义单调的 枚举值,就报错了,必须所有枚举值,保持一致的效果
    // 2. 枚举的 主构造的参数 必须和 枚举(的参数) 保持一致

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

    fun updateData(limbsInfo: LimbsInfo) {
        println("更新前的数据是:${this.limbsInfo}")
        this.limbsInfo.limbsInfo = limbsInfo.limbsInfo
        this.limbsInfo.length = limbsInfo.length
        println("更新后的数据是:${this.limbsInfo}")
    }
}

// TODO 96-Kotlin语言的枚举类定义函数学习
fun main() {
    // 显示枚举值

    // 一般不会这样用
    /*println(Limbs.show())
    println(Limbs().show())*/

    // 一般的用法如下:
    println(Limbs.LEFT_HAND.show())
    println(Limbs.RIGHT_HAND.show())
    println(Limbs.LEFT_FOOT.show())
    println(Limbs.RIGHT_FOOT.show())

    println()

    // 更新枚举值
    Limbs.RIGHT_HAND.updateData(LimbsInfo("右手2", 99))
    Limbs.LEFT_HAND.updateData(LimbsInfo("左手2", 99))
    Limbs.LEFT_FOOT.updateData(LimbsInfo("左脚2", 199))
    Limbs.RIGHT_FOOT.updateData(LimbsInfo("右叫2", 199))
}

42、Kotlin语言的代数数据类型

enum class Exam {
    Fraction1, // 分数差
    Fraction2, // 分数及格
    Fraction3, // 分数良好
    Fraction4, // 分数优秀

    ; // 枚举结束

    // 需求 得到优秀的孩子姓名
    var studentName: String? = null
    // 我们用枚举类,要做到此需求,就非常的麻烦了,很难做到而已,不是做不到
    //  需求:引出 密封类
}

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

// TODO 97-Kotlin语言的代数数据类型
// 1.定义枚举Exam类,四个级别分数情况
// 2.定义Teacher老师类,when使用枚举类
// 3.需求 得到优秀的孩子姓名
fun main() {
    println(Teacher(Exam.Fraction1).show())
    println(Teacher(Exam.Fraction3).show())
}

43、Kotlin语言的密封类学习

// 密封类,我们成员, 就必须有类型 并且 继承本类
sealed class Exams {
    // object? Fraction1 Fraction3 都不需要任何成员,所以一般都写成object,单例就单例,无所谓了
    object Fraction1 : Exams() // 分数差
    object Fraction2 : Exams() // 分数及格
    object Fraction3 : Exams() // 分数良好

    // 假设 Fraction4 是可以写object的,那么也不合理,因为对象不是单例的,有 对象1李四 对象2王五
    class Fraction4(val studentName : String) : Exams() // 分数优秀

    // 需求 得到优秀的孩子姓名
    // var studentName: String? = null
    // 我们用枚举类,要做到此需求,就非常的麻烦了,很难做到而已,不是做不到
    //  需求:引出 密封类
}

class Teachers (private val exam: Exams) {
    fun show() =
        when (exam) {
            is Exams.Fraction1 -> "该学生分数很差"
            is Exams.Fraction2 -> "该学生分数及格"
            is Exams.Fraction3 -> "该学生分数良好"
            is Exams.Fraction4 -> "该学生分数优秀:该学生的姓名是:${(this.exam as Exams.Fraction4).studentName}"
        }
}

// TODO 98-Kotlin语言的密封类学习
fun main() {
    println(Teachers(Exams.Fraction1).show())
    println(Teachers(Exams.Fraction2).show())
    println(Teachers(Exams.Fraction3).show())
    println(Teachers(Exams.Fraction4("李四")).show()) // 对象1
    println(Teachers(Exams.Fraction4("王五")).show()) // 对象2

    println(Exams.Fraction1 === Exams.Fraction1) // true, === 必须对象引用, object是单例 只会实例化一次

    println(Exams.Fraction4("AAA") === Exams.Fraction4("AAA")) // class 有两个不同的对象,所以是false
}

44、Kotlin语言的接口定义

interface IUSB {
    var usbVersionInfo: String // USB版本相关的信息
    var usbInsertDevice: String // USB插入的设备信息

    fun insertUBS() : String
}

// 鼠标UBS实现类
class Mouse(override var usbVersionInfo: String = "USB 3.0",
            override var usbInsertDevice: String = "鼠标接入了UBS口") :IUSB {

    override fun insertUBS() = "Mouse $usbVersionInfo, $usbInsertDevice"
}

// 键盘USB实现类
class KeyBoard : IUSB {

    override var usbVersionInfo: String = "USB 3.1"
        // 下面的 set get 都会持有 field,现在是你没有给 usbVersionInfo 赋值, 意味着field是没法让set/get持有的
        get() = field
        set(value) {
            field = value
        }

    override var usbInsertDevice: String = "键盘接入了UBS口"
        get() {
            println("@你get了[${field}]值出去了")
            return field
        }
        set(value) {
            field = value
            println("@你set了[${value}]值进来了")
        }

    override fun insertUBS(): String = "KeyBoard $usbVersionInfo, $usbInsertDevice"
}

// 1.接口里面的所有成员 和 接口本身 都是 public open 的,所以不需要open,这个是接口的特殊
// 2.接口不能有主构造,反正就是没有构造
// 3.实现类不仅仅要重写接口的函数,也要重写 接口的成员
// 4.接口实现代码区域,全部都要增加 override 关键字来修饰
fun main() {
    val iusb1 : IUSB = Mouse()
    println(iusb1.insertUBS())

    println()

    val iusb2: IUSB = KeyBoard()
    println(iusb2.insertUBS())

    iusb2.usbInsertDevice = "AAA"
}

45、Kotlin 每个字段都有set和get方法

interface USB2 {

    // 1.接口 var 也是不能给接口的成员赋值的 (但是有其他办法)
    // 2.任何类 接口 等等  val 代表只读的,是不可以在后面动态赋值 (也有其他办法)

    val usbVersionInfo: String // USB版本相关的信息
       get() = (1..100).shuffled().last().toString()
       // val 不需要set

    val usbInsertDevice: String // USB插入的设备信息
        get() = "高级设备接入USB"
        // val 不需要set

    fun insertUBS() : String
}

46、Kotlin语言的定义泛型类

class KtBase103<T> (private val obj: T) { // 万能输出器
    fun show() = println("万能输出器:$obj")
}

data class Student(val name: String , val age: Int, val sex: Char)
data class Teacher(val name: String , val age: Int, val sex: Char)

// TODO 103-Kotlin语言的定义泛型类
// 1.定义 对象输出器 println(obj)
// 2.定义两个对象,三个属性
// 3.对象 String Int Double Float Char 等 测试 对象输出器
fun main() {
    val stu1 = Student("张三", 88, '男')
    val stu2 = Student("李四", 78, '女')

    val tea1 = Teacher("王五", 77, '男')
    val tea2 = Teacher("赵六", 89, '女')

    KtBase103(stu1).show()
    KtBase103(stu2).show()
    KtBase103(tea1).show()
    KtBase103(tea2).show()

    KtBase103(String("刘一".toByteArray())).show()

    KtBase103(575).show()
    KtBase103(53456.45).show()
    KtBase103(4645.5f).show()
    KtBase103('男').show()

}

47、Kotlin语言的泛型变换实战

// 1.类 isMap map takeIf  map是什么类型
class KtBase105<T>(val isMap: Boolean = false, val inputType: T) {

    // 模仿RxJava  T是要变化的输入类型   R是变换后的输出类型
    // 要去map返回的类型是 R?  == 有可能是R 有可能是null
    inline fun <R> map(mapAction: (T) -> R) = mapAction(inputType).takeIf { isMap }
}

inline fun <I, O> map(inputValue : I , isMap: Boolean = true, mapActionLambda : (I) -> O) =
    if (isMap) mapActionLambda(inputValue) else null

// TODO 105-Kotlin语言的泛型变换实战
// 1.类 isMap map takeIf  map是什么类型
// 2.map int -> str 最终接收是什么类型
// 3.map per -> stu 最终接收是什么类型
// 4.验证是否是此类型 与 null
fun main() {

    // 2.map int -> str 最终接收是什么类型
    val p1 = KtBase105(isMap = /*true*/ false, inputType = 5434)

    val r = p1.map {
        it
        it.toString() // lambda最后一行是 返回值
        "我的it是:$it" // lambda最后一行是 返回值
    }

    // 4.验证是否是此类型 与 null
    val str1: String = "OK1"
    val str2: String? = "OK2"
    println(r is String)
    println(r is String?)
    println(r ?: "大哥你是null,你在搞什么飞机...,你是不是传入了isMap是false")

    println()

    // 3.map per -> stu 最终接收是什么类型
    val p2 = KtBase105(true, Persons("李四", 99))
    val r2 : Students? = p2.map {
        // it == Persons对象 == inputType
        it
        Students(it.name, it.age)
    }
    println(r2)

    println()

    // map函数 模仿RxJava变换操作
    val r3 = map(123) {
        it.toString()
        "map包裹[$it]" // lambda表达式最后一行,就是返回值
    }
    println(r3)

    123.run {  }
}

data class Persons(val name: String, val age: Int)
data class Students(val name: String, val age: Int)

48、Kotlin语言的out-协变学习

package com.derry.s6

// 生产者 out T  协变 [out T 此泛型能够被获取 读取 所以是out]
interface Producer<out T> {

    // out T  代表整个生产者类里面  这个T  只能被读取,不能被修改了

    // 不能被修改了 (编译不通过)
    // fun consumer(itme: T)  /*{  消费代码  }*/

    // 只能被读取
    fun producer() : T
}

// 消费者 in T  逆变 [in T 此泛型只能被修改 更新 所以是in]
interface Consumer <in T> {
    // out T  代表整个生产者类里面  这个T  只能被读取,不能被修改了

    // 只能被修改了
    fun consumer(itme : T) /*{  消费代码  }*/

    // 不能被读取 (编译不通过)
    // fun producer() : T
}

// 生产者&消费者 T  默认情况下,是不变
interface ProducerAndConsumer<T> {
    // 能被修改了
    fun consumer(itme : T) /*{  消费代码  }*/

    // 能被读取
    fun producer() : T
}

open class Animal // 动物
open class Humanity : Animal() // 人类
open class Man : Humanity() // 男人
open class WoMan : Humanity() // 女人

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  只管生产者
class ProducerClass1 : Producer<Animal> {
    override fun producer(): Animal {
        println("生产者 Animal")
        return Animal()
    }
}

class ProducerClass2 : Producer<Humanity> {
    override fun producer(): Humanity {
        println("生产者 Humanity")
        return Humanity()
    }
}

class ProducerClass3 : Producer<Man> {
    override fun producer(): Man {
        println("生产者 Man")
        return Man()
    }
}

class ProducerClass4 : Producer<WoMan> {
    override fun producer(): WoMan {
        println("生产者 WoMan")
        return WoMan()
    }
}

// TODO 109-Kotlin语言的out-协变学习
// 1.Producer Consumer 不变
// 2.ProducerClass4
// 3.main 测试
fun main() {
    val p1 : Producer<Animal> = ProducerClass1() // ProducerClass1他本来就是 传递 Animal ,当然是可以的

    val p2 : Producer<Animal> = ProducerClass2() // ProducerClass2他本来就是 传递 Humanity,居然也可以,因为out
    val p3 : Producer<Animal> = ProducerClass3() // ProducerClass3他本来就是 传递 Man,居然也可以,因为out
    val p4 : Producer<Animal> = ProducerClass4() // ProducerClass4他本来就是 传递 WoMan,居然也可以,因为out

    // 泛型默认情况下是:泛型的子类对象 不可以赋值给 泛型的父类对象
    // 泛型默认情况下是:泛型具体处的子类对象  不可以赋值给 泛型声明处的父类对象

    // out: 泛型的子类对象 可以赋值给 泛型的父类对象
    // out: 泛型具体出的子类对象 可以赋值给 泛型声明处的父类对象

    // 协变:父类 泛型声明处  可以接收   子类 泛型具体处
}

49、Kotlin语言的in-逆变学习

package com.derry.s6

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>  只管消费者
class ConsumerClass1 : Consumer<Animal> {
    override fun consumer(item: Animal) {
        println("消费者 Animal")
    }
}

class ConsumerClass2 : Consumer<Humanity> {
    override fun consumer(item: Humanity) {
        println("消费者 Humanity")
    }
}

class ConsumerClass3 : Consumer<Man> {
    override fun consumer(item: Man) {
        println("消费者 Man")
    }
}

class ConsumerrClass4 : Consumer<WoMan> {
    override fun consumer(item: WoMan) {
        println("消费者 WoMan")
    }
}

// TODO 110-Kotlin语言的in-逆变学习
fun main() {
    val p1 : Consumer<Man> = ConsumerClass1() // ConsumerClass1他本来就是 传递 Animal,居然也可以,因为in
    val p2 : Consumer<WoMan> = ConsumerClass2() // ConsumerClass1他本来就是 传递 Humanity,居然也可以,因为in

    // 默认情况下: 泛型具体出的父类  是不可以赋值给  泛型声明处的子类的
    // in:泛型具体出的父类  是可以赋值给  泛型声明处的子类的

    // 逆变:子类 泛型声明处  可以接收   父类 泛型具体处


    // 协变:out 父类 = 子类
    // 逆变:in  子类 = 父类
}

50、Kotlin语言中使用in和out

package com.derry.s6

// in T  out T 声明处指定关系  声明处泛型  这个是Java没有的功能

// 整个 SetClass 里面的所有成员 泛型相关,只能修改 更改,
//                                    不能获取人家 读取人家的
// 小结:当我们 对这个整个类里面的泛型,只能修改 ,不能让外界读取时,可以声明 in T 逆变
class SetClass<in T>() {

    // 200个函数 这200个函数 对T只能修改,不能给外界读取
    // ...

    fun set1(item: T) {
        println("set1 你要设置的item是:$item")
    }

    fun set2(item: T) {
        println("set2 你要设置的item是:$item")
    }

    fun set3(item: T) {
        println("set3 你要设置的item是:$item")
    }

    // ...

    // 不能给外界读取 (增加in后,不能给外界读取,所以编译不通过)
    /*fun get1() : T? {
        return null
    }

    fun get2() : T? {
        return null
    }

    fun get3() : T? {
        return null
    }*/

    // ...
}


// 整个 GetClass 里面的所有成员 泛型相关,不能修改 更改,
//                                    只能获取人家 读取人家的
// 小结:当我们 对这个整个类里面的泛型,只能给读取 ,不能修改 更改,可以声明 out T 协变
class GetClass<out T>(_item: T) {

    val item: T = _item

    // 200个函数 这200个函数 对T只能读取,不能给外界修改 更改
    // ...

    // 不能给外界修改 更改 (增加out后,不能给外界修改 更改,所以编译不通过)
    /*fun set1(item : T) {
        println("set1 你要设置的item是:$item")
    }

    fun set2(item : T) {
        println("set2 你要设置的item是:$item")
    }

    fun set3(item : T) {
        println("set3 你要设置的item是:$item")
    }*/

    // ...


    fun get1(): T {
        return item
    }

    fun get2(): T {
        return item
    }

    fun get3(): T? {
        return item
    }

    // ...
}

// TODO 111-Kotlin语言中使用in和out
fun main() {
    // 逆变 in T  SetClass 只能修改 更改 不能给外界读取
    val p1 = SetClass<String>()
    p1.set1("Derry")
    p1.set2("Kevin")

    println()

    // 协变 out T GetClass 只能读取,不能修改 更改
    val p2 = GetClass("李四")
    println(p2.get1())
    val p3 = GetClass("王五")
    println(p3.get3())
}

51、Kotlin语言的reified关键字学习

package com.derry.s6

// 1.定义3个Obj类
data class ObjectClass1(val name: String, val age: Int, val study: String)
data class ObjectClass2(val name: String, val age: Int, val study: String)
data class ObjectClass3(val name: String, val age: Int, val study: String)

class KtBase112 {

    // 所有的功能,写在函数上
    // 默认随机输出一个对象,如果此对象和用户指定的对象不一致,我们就启用备用对象,否则就直接返回对象
    inline fun <reified T> randomOrDefault(defaultLambdaAction: () -> T ) :T? {
        val objList : List<Any> = listOf(ObjectClass1("obj1 李四", 22, "学习C"),
                                         ObjectClass2("obj2 王五", 23, "学习C++"),
                                         ObjectClass3("obj3 赵六", 24, "学习C#"))

        val randomObj : Any? = objList.shuffled().first()

        println("您随机产生的对象 幸运儿是:$randomObj")

        // return randomObj.takeIf { it is T } as T ?: null     :T? {

        // T  与  T?  是不同的 ?
        // 答: it is T false  takeIf  null    null as T 奔溃了,解决思路: null as T?

        // 如果  it随机产生的对象 等于 T类型的,就会走 as T 直接返回了
        return randomObj.takeIf { it is T } as T?  // null as T     null as T?
            // 如果  it随机产生的对象 不等于 T类型的,就会走下面这个备用环节
            ?: defaultLambdaAction()
    }

}

// TODO 112-Kotlin语言的reified关键字学习
// 1.定义3个Obj类
// 2.randomOrDefault函数 备用机制的lambda
// 3.lists.shuffled()
fun main() {
    val finalResult = KtBase112().randomOrDefault<ObjectClass1> {
        println("由于随机产生的对象 和 我们指定的ObjectClass1不一致,所以启用备用对象")
        ObjectClass1("备用 obj1 李四", 22, "学习C") // 最后一行的返回
    }
    println("客户端最终结果:$finalResult")
}

52、Kotlin语言的泛型扩展函数

package com.derry.s6

// 1.String类型就输出长度
fun <T> T.showContentInfo() = println("${if (this is String) "你的字符串长度是:$length" else "你不是字符串 你的内容是:$this"}")

// 2.显示调用时间
fun <I> I.showTime() = println("你当前调用的时间是:${System.currentTimeMillis()}, 内容是:$this")

// 3.显示调用者的类型
fun <INPUTTYPE> INPUTTYPE.showTypesAction() =
    when(this) {
        is String -> "原来你是String类型"
        is Int -> "原来你是Int类型"
        is Char -> "原来你是Char类型"
        is Float -> "原来你是Float类型"
        is Double -> "原来你是Double类型"
        is Boolean -> "原来你是Boolean类型"
        is Unit -> "原来你是无参返回函数类型"
        else -> "未知类型"
    }

fun commonFun() {}

// fun commonFun2() = "DDD" 这个不管他

// TODO 115-Kotlin语言的泛型扩展函数
// 1.String类型就输出长度
// 2.显示调用时间
// 3.显示调用者的类型
fun main() {
    345.showContentInfo()
    'C'.showContentInfo()
    false.showContentInfo()
    345.45f.showContentInfo()
    53454.45.showContentInfo()
    "Derry".showContentInfo()
    commonFun().showContentInfo()
    // commonFun2().showContentInfo()
    // 太多了,不写了 .... 省略

    // 所有类型 都是泛型,你对泛型扩展了showContentInfo,那么所有类型都可以使用showContentInfo

    println()

    345.showTime()
    'C'.showTime()
    false.showTime()
    345.45f.showTime()
    53454.45.showTime()
    "Derry".showTime()
    commonFun().showTime()
    // commonFun2().showTime()
    // 太多了,不写了 .... 省略

    println()

    println(345.showTypesAction())
    println('C'.showTypesAction())
    println(false.showTypesAction())
    println(345.45f.showTypesAction())
    println(53454.45.showTypesAction())
    println("Derry".showTypesAction())
    println(commonFun().showTypesAction())
    // println(commonFun2().showTypesAction())
}

53、Kotlin语言的标准函数与泛型扩展函数

package com.derry.s6

// TODO 116-Kotlin语言的标准函数与泛型扩展函数
fun main() {
    val r: Char = "Derry".mLet {
        it
        true
        "OK"
        'A'
    }

    123.mLet {
        it
    }

    'C'.mLet {
        it
    }

    // 万能类型,任何类型,所有类型,都可以使用我的 mLet
    // 省略几万行代码 ...

    val r2 : String = "Derry2".let {
        it
        34543.45f
        "Derry"
    }
}

// private 私有化
// inline  我们的函数是高阶函数,所以用到内联,做lambda的优化,性能提高
// fun<I, O> 在函数中,申明两个泛型,函数泛型  I输入Input, O输出Output
// I.mLet 对I输入Input进行函数扩展,扩展函数的名称是 mLet,意味着,所有的类型,万能类型,都可以用 xxx.mLet
// lambda : (I) -> O   (I输入参数) -> O输出
//  : O  会根据用户的返回类型,变化而变化
// lambda(this) I进行函数扩展,在整个扩展函数里面,this == I本身
private inline fun<I, O> I.mLet(lambda : (I) -> O) : O = lambda(this)

54、Kotlin语言的扩展属性

package com.derry.s6

// 你必须把前面的普通方式学会:
val myStr : String = "AAA"
/* 背后代码:
   public final class KtBase117Kt {

       @NotNull
       private static final String myStr = "AAA";

       @NotNull
       public static final String getMyStr() {
            return myStr;
       }
   }
 */

// 扩展属性:
val String.myInfo: String
    get() = "Derry"

/* 背后代码:

   public final class KtBase117Kt {

       真实情况:
       @NotNull
       public static final String getMyInfo(@NotNull String $this$myInfo) {
          Intrinsics.checkParameterIsNotNull($this$myInfo, "$this$myInfo");
          return "Derry";
       }
   }

 */

// 打印输出 并且 链式调用 (只有String有资格这样)
fun String.showPrintln() : String {
    println("打印输出 并且 链式调用 (只有String有资格这样):内容$this")
    return this
}

val String.stringAllInfoValueVal
    get() = "当前${System.currentTimeMillis()}这个时间点被调用了一次,当前的值是:$this,当前字符串长度是:$length"

// TODO 117-Kotlin语言的扩展属性
fun main() {
    val str : String = "ABC"
    println(str.myInfo)

    str.showPrintln().showPrintln().showPrintln().showPrintln()

    str.myInfo.showPrintln().showPrintln().showPrintln()

    "Derry老师".stringAllInfoValueVal // 扩展属性
        .showPrintln().showPrintln().showPrintln().showPrintln() // 扩展函数

}

55、内置函数的总结

/**
 * 内置函数的总结:
 *
 * TODO apply:info.apply
 * 1.apply函数返回类型,永远都是info本身 此条和 also 一模一样
 * 2.apply函数的 匿名函数里面持有的是this == info本身  此条和 run一模一样
 *
 * TODO let:集合.let
 * 1.let函数返回类型,是根据匿名函数最后一行的变化而变化  此条和 run 一模一样
 * 2.let函数的 匿名函数里面持有的是it == 集合本身  此条和 also 一模一样
 */

TODO run: str.run
1.run函数返回类型,是根据匿名函数最后一行的变化而变化  此条和 let一模一样
2.run函数的 匿名函数里面持有的是this == str本身     此条和 apply一模一样

TODO with with(str)   with和run基本上一样,只不过就是使用的时候不同
1.with函数返回类型,是根据匿名函数最后一行的变化而变化  此条和 let一模一样
2.with函数的 匿名函数里面持有的是this == str本身     此条和 apply一模一样

TODO also str.also
1.also函数返回类型,永远都是str本身  此条和 apply 一模一样
2.also函数的 匿名函数里面持有的是it == str  此条和 let 一模一样


Todo =================================   apply 与 also 是一个类别的 属于一类的    =================================
相同点:apply与also返回类型,是一样的: 他们永远都是返回info本身,匿名函数,最后一行无法作为返回值,不影响函数返回类型
不同点:匿名函数里面 apply{ 持有this setFilexxx() }  alos { 持有it it.setFilexxx() }
应用点:
       val file本身 = File("xx").apply { setFilexxx() ... }.apply { ... }.apply { ... } 链式调用
       val file本身 = FIle("xx").also { it.setFilexxx() ... }.also { ... }.also { ... } 链式调用

val info本身 = info.apply {
    this == info本身
    ...
    "Derry"
}.apply {
}.apply {
}
val info本身 = info.also {
    it == info本身
    ...
    true
}.also {
}.also {
}


Todo =================================   run 与 let 与 with 是一个类别的 属于一类的    =================================
相同点:run与let返回类型,是一样的,都会根据匿名函数最后一行返回类型而决定 run与let的返回类型(是根据匿名函数最后一行的变化而变化)
不同点:匿名函数里面 run持有this  let持有it
应用点:
      info.run { show("内容:$this") show("内容长度:$length") show("${if (this is String) 你是String类型 else 你不是String类型}") }
      info.let  { show("内容:it") show("内容长度:$it.length") show("${if (it is String) 你是String类型 else 你不是String类型}") }

val r : Boolean类型 = info.run {  this == info本身
    length

    545
    454.545
    534543.5f
    true // 最后一行
}

val r : Char类型 = info.let {  it == info本身
    it.length

    545
    454.545
    534543.5f
    true
    'A' // 最后一行
}

TODO >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>> 下面是with

上面的 run 使用环节:  info.run {}
下面的 with 使用环节:  with(info) {}

相同点:with与run与let返回类型,是一样的,都会根据匿名函数最后一行返回类型而决定 run与let的返回类型(是根据匿名函数最后一行的变化而变化)
不同点:匿名函数里面 run持有this  let持有it  with持有this
应用点:
      info.run { show("内容:$this") show("内容长度:$length") show("${if (this is String) 你是String类型 else 你不是String类型}") }
      info.let  { show("内容:it") show("内容长度:$it.length") show("${if (it is String) 你是String类型 else 你不是String类型}") }
      with(info)  { show("内容:this") show("内容长度:$length") show("${if (this is String) 你是String类型 else 你不是String类型}") }


TODO =======================================  let 与 apply 内部源码原理分析

// 1. let的返回类型是 根据匿名函数的变化而变化(lambda的返回类型变化而变化)
// 2. 匿名函数里面持有的是 it == I == info本身
inline fun <I, O> I.let(lambda : (I) -> O) = lambda(this)

// 1. apply的返回类型是 永远都是I(所以你可以链式调用) (lambda的返回类型 无法变化,你写的是 Unit,并且 没有和lambda关联返回类型)
// 2. 匿名函数里面持有的是 this == I == info本身
inline fun <I> I.apply(lambda : I.() -> Unit) : I {
    lambda()
    return this
}

56、Kotlin语言的可空类型扩展函数

package com.derry.s6

// 对 String?==可空类型的 进行函数扩展,并且有备用值
fun String?.outputStringValueFun(defalutValue : String) = println(this ?: defalutValue)

// 编译期非常智能:能够监测到你做了if判断(能够对你代码逻辑监测),就知道后续类型
fun String?.outputStringValueFunGet(defaultValue : String) = if (this == null) defaultValue else this

// TODO 118-Kotlin语言的可空类型扩展函数
// 如果是null,就输出默认值
fun main() {
    val infoValue : String ? = null // infoValue是可空的类型  String  String?==可空类型的
    infoValue.outputStringValueFun("我是默认值啊1")

    // String? 前面已经说过了,可以接收 可空数据  也可以接收 有值数据
    // String  前面已经说过了,只能接收 有值数据
    val name = "Derry"
    name.outputStringValueFun("我是默认值啊2")

    // >>>>>>>>>>>>>>
    println(infoValue.outputStringValueFunGet("我是默认值啊3"))
    println(name.outputStringValueFunGet("我是默认值啊4"))
}

57、Kotlin语言的infix关键字

package com.derry.s6

// 自定义的中缀表达式 + 扩展函数 一起用的     使用者: "一".gogogo(1)  "一" gogogo 1
// 1.条件一  对第一个参数 C1.gogogo  函数扩展
// 2.条件二  需要在 括号(c2: C2) 参数里面,传递一个参数
private infix fun <C1, C2> C1.gogogo(c2: C2) {
    // 做很多的逻辑
    // ...
    // 省略几万行代码
    println("我们的中缀表达式,对一个参数的内容是:$this")
    println("我们的中缀表达式,对二个参数的内容是:$c2")
}

// TODO 119-Kotlin语言的infix关键字
// infix == 中缀表达式 可以简化我的代码
fun main() {
    // 下面是我们map自带的中缀表达式
    mapOf("零".to(0))

    mapOf("一" to 1)
    mapOf("二" to 2)
    mapOf("三" to 3)

    // 下面是我们自己写的中缀表达式
    123 gogogo '男'
    "Derry".gogogo('M')
    "Derry2" gogogo 'M'
}

58、Kotlin语言的定义扩展文件

package com.derry.s6.com.derry

// 1.扩展文件一般都是public,如果private外界无法使用
// 2.Iterable<E> 子类 set list 都可以用,所以用父类
// 3.本次扩展函数的作用是,随机取第一个元素返回
fun <E> Iterable<E>.randomItemValue() = this.shuffled().first()

fun <T> Iterable<T>.randomItemValuePrintln() = println(this.shuffled().first())
...
package com.derry.s6

// 导入扩展文件
// 在工作中非常有用,可以把很多的扩展操作,写到某一个地方,到时候引入过来用,比较独立化
import com.derry.s6.com.derry.randomItemValue
import com.derry.s6.com.derry.randomItemValuePrintln

// TODO 120-Kotlin语言的定义扩展文件
fun main() {
    val list : List<String> = listOf("李元霸", "李连杰", "李小龙")
    val set : Set<Double> = setOf(545.5, 434.5, 656.6)

    // 如果不使用 扩展文件
    println(list.shuffled().first())
    println(set.shuffled().first())

    println()

    // 使用 扩展文件
    println(list.randomItemValue())
    println(set.randomItemValue())

    println()

    list.randomItemValuePrintln()
    set.randomItemValuePrintln()
}

59、Kotlin语言的重命名扩展学习

package com.derry.s6

import com.derry.s6.com.derry.randomItemValue as g  // as g 重命名扩展操作
import com.derry.s6.com.derry.randomItemValuePrintln as p // as g 重命名扩展操作

// TODO 121-Kotlin语言的重命名扩展学习
fun main() {

    val list : List<String> = listOf("李元霸", "李连杰", "李小龙")
    val set : Set<Double> = setOf(545.5, 434.5, 656.6)

    // 使用 扩展文件
    println(list.g())
    println(set.g())

    println()

    list.p()
    set.p()
}

60、Kotlin语言的DSL学习

package com.derry.s6

import java.io.File

class Context {

    val info = "我就是Derry"
    val name = "DDD"

    fun toast(str: String) = println("toast:$str")
}

inline fun Context.apply5(lambda: Context.(String) -> Unit): Context {
    lambda(info)
    return this
}

// >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>
inline fun File.applyFile(action: (String, String?) -> Unit): File {
    setWritable(true)
    setReadable(true)
    action(name, readLines()[0])
    return this
}

// TODO 123-Kotlin语言的DSL学习
// DSL简介 所谓DSL领域专用语言(Domain Specified Language/ DSL)
fun main() {

    // 其实apply5函数,就是DSL编程范式,定义输入输出等规则:
    // 1.定义整个lambda规则标准,输入 必须是Context这个类,才有资格调用apply5函数,匿名函数里面持有it 和 this
    // 2.定义整个lambda规则标准,输出 我们会始终返回Context本身,所以你可以链式调用
    // 然后main函数就可以根据DSL编程方式标准规则,来写具体的实现,这就是DSL编程范式
    val context : Context = Context().apply5 {
        // it == String == "我就是Derry"
        println("我的it是:$it,我的this是:$this")
        toast("success")
        toast(it)
        toast(name)
        true
    }.apply5 { }.apply5 { }.apply5 { } // ...
    println()
    println("我始终是输出Context本身:" + context.info)

    println()

    // 其实applyFile函数,就是DSL编程范式,定义输入输出等规则:
    // 1.定义整个lambda规则标准,输入 必须是File类,才有资格调用applyFile函数,匿名函数里面持有 fileName,data
    // 2.定义整个lambda规则标准,输出 我们始终返回File对象本身,所以你可以链式调用
    // 然后main函数就可以根据DSL编程方式标准规则,来写具体的实现,这就是DSL编程范式
    val file: File = File("D:\\a.txt")
        .applyFile { fileName, data ->
            println("你的文件名是:$fileName, 你的文件里面的数据是:$data")
            println("你的文件名是:$fileName, 你的文件里面的数据是:$data")
            println("你的文件名是:$fileName, 你的文件里面的数据是:$data")
            true
        }.applyFile { a, b -> }.applyFile { a, b -> }.applyFile { a, b -> } // ...

    println("我始终是输出File本身:${file.name}")
}

61、Kotlin语言的变换函数-map

package com.derry.s6

// TODO 124-Kotlin语言的变换函数-map
fun main() {
    val list = listOf("李元霸", "李连杰", "李小龙")
    // T T T  --->  新的集合(R, R, R)
    // 原理:就是把你 匿名函数 最后一行的返回值 加入一个新的集合,新集合的泛型是R,并且返回新集合
    val list2 : List<Int> = list.map {
        // it = T == 元素 == String
        "【$it】"
        88
    }
    println(list2)

    // 用途: 和 RxJava的思路,一模一样
    val list3 : List<String> = list.map {
        "姓名是:$it"
    }.map {
        "$it,文字的长度是:${it.length}"
    }.map {
        "【$it】"
    }
    for (s in list3) {
        print("$s  ")
    }

    println()

    list.map {
        "姓名是:$it"
    }.map {
        "$it,文字的长度是:${it.length}"
    }.map {
        "【$it】"
    }.map {
        print("$it  ")
    }
}

62、Kotlin语言的变换函数-flatMap

package com.derry.s6

// TODO 125-Kotlin语言的变换函数-flatMap
// map {返回类型:T String Int Boolean Char ...  是把每一个元素(String)加入到新集合,最后返回新集合 List<String>}
// flatMap {返回类型:每一个元素 T 集合1 集合2 集合3 ... 是把每一个元素(集合)加入到新集合,最后返回新集合 List<List<String>> 最终内部会处理成List<String>}

// TODO flatMap 相当于 List<List<String>> 集合的集合,有嵌套关系

fun main() {
    val list : List<String> = listOf("李四", "王五", "赵六", "初七")

    val newList : List<String> = list.map {
        "你的姓名是:$it" // 每次返回一个 String
    }.map {
        "$it, 你文字的长度是:${it.length}" // 每次返回一个 String
    }.flatMap {
        listOf("$it 在学习C++", "$it 在学习Java", "$it 在学习Kotlin") // 每次返回一个集合,四次
    }
    println(newList)

    println()

    /*
    [你的姓名是:李四, 你文字的长度是:8 在学习C++,
     你的姓名是:李四, 你文字的长度是:8 在学习Java,
     你的姓名是:李四, 你文字的长度是:8 在学习Kotlin,

     你的姓名是:王五, 你文字的长度是:8 在学习C++,
     你的姓名是:王五, 你文字的长度是:8 在学习Java,
     你的姓名是:王五, 你文字的长度是:8 在学习Kotlin,

     你的姓名是:赵六, 你文字的长度是:8 在学习C++,
     你的姓名是:赵六, 你文字的长度是:8 在学习Java,
     你的姓名是:赵六, 你文字的长度是:8 在学习Kotlin,

     你的姓名是:初七, 你文字的长度是:8 在学习C++,
     你的姓名是:初七, 你文字的长度是:8 在学习Java,
     你的姓名是:初七, 你文字的长度是:8 在学习Kotlin]
     */

    val newList2 : List<String> = list.flatMap {
        listOf("$it 在学习C++", "$it 在学习Java", "$it 在学习Kotlin")
    }
    println(newList2)
    //[李四 在学习C++,
    // 李四 在学习Java,
    // 李四 在学习Kotlin,
    // 王五 在学习C++,
    // 王五 在学习Java,
    // 王五 在学习Kotlin,
    // 赵六 在学习C++,
    // 赵六 在学习Java,
    // 赵六 在学习Kotlin,
    // 初七 在学习C++,
    // 初七 在学习Java,
    // 初七 在学习Kotlin]

    // 原理:就是把你 匿名函数 最后一行的返回值(又是一个集合listOf(......)) 加入一个新的集合,新集合的泛型是R,并且返回新集合
}

63、Kotlin语言的合并函数-zip

package com.derry.s6

// TODO 127-Kotlin语言的合并函数-zip
fun main() {
    val names = listOf("张三", "李四", "王五")
    val ages = listOf(20, 21, 22)

    // RxJava zip 合并操作符
    // KT 自带就有zip 合并操作

    // 原理:就是把 第一个集合 和 第二个集合 合并起来,创建新的集合,并返回
    //      创建新的集合(元素,元素,元素) 元素Pair(K, V)  K代替第一个集合的元素   V代替第二个集合的元素
    val zip : List<Pair<String, Int>> = names.zip(ages)
    println(zip)
    println(zip.toMap())
    println(zip.toMutableSet())
    println(zip.toMutableList())

    println()

    // 遍历
    zip.forEach {
        // it == Pair<String, Int>
        println("姓名是:${it.first}, 年龄是:${it.second}")
    }

    println()

    // map 普通方式
    zip.toMap().forEach { k, v ->
        println("姓名是:${k}, 年龄是:${v}")
    }

    println()

    // map 解构的方式
    zip.toMap().forEach { (k, v) ->
        println("姓名是:${k}, 年龄是:${v}")
    }

    println()

    zip.toMap().forEach {
        // it == Map的元素 每一个元素 有K和V,  Map.Entry<String, Int>
        // it == Pair<String, Int>
        println("姓名是:${it.key}, 年龄是:${it.value}")
    }
}

64、Kotlin 单例

// 1.饿汉式的实现  KT版本
object SingletonDemoKt
// 2.懒汉式的实现  KT版本
class SingletonDemo2Kt {

    companion object {

        private var instance : SingletonDemo2Kt? = null
            get() {
                if (field == null) {
                    field = SingletonDemo2Kt()
                }
                return field
            }

        fun getInstanceAction() = instance!!
    }

    fun show() {
        println("show")
    }
}

fun main() {
    SingletonDemo2Kt.getInstanceAction().show()
}

// 3.懒汉式的实现  KT版本 安全
class SingletonDemo3Kt {

    companion object {

        private var instance : SingletonDemo2Kt? = null
            get() {
                if (field == null) {
                    field = SingletonDemo2Kt()
                }
                return field
            }

        @Synchronized
        fun getInstanceAction() = instance!!
    }

    fun show() {
        println("show")
    }
}

fun main() {
    SingletonDemo3Kt.getInstanceAction().show()
}

// 4.懒汉式的实现 双重校验安全  KT版本
class SingletonDemo4Kt private constructor() {

    companion object {
        val instance : SingletonDemo4Kt by lazy (mode = LazyThreadSafetyMode.SYNCHRONIZED) { SingletonDemo4Kt() }
    }

    fun show() {
        println("show")
    }
}

fun main() {
    SingletonDemo4Kt.instance.show()
}

65、注解@JvmName与Kotlin

@file:JvmName("Stu") // 就是在编译器环节,修改我们的类的名字,让Java端调用更简洁

package com.derry.s7

// @file:JvmName("Stu") 注意:必须写在 包名的外面

// TODO 131-注解@JvmName与Kotlin

fun getStudentNameValueInfo(str : String) = println(str)

fun main() {}

/* 背后生成的代码:

    public final class KtBase131Kt {

        public static final void getStudentNameValueInfo(@NotNull String str) {
            System.out.println(str);
        }

        public static final void main() {
        }

        public static void main(String[] args) {
            main();
        }
    }


    @file:JvmName("Stu") 背后的原理
    public final class Stu {

        public static final void getStudentNameValueInfo(@NotNull String str) {
            System.out.println(str);
        }

        public static final void main() {
        }

        public static void main(String[] args) {
            main();
        }
    }
 */
public class KtBase131 {

    public static void main(String[] args) {
        // KtBase131Kt.getStudentNameValueInfo("Derry is OK");
        //java端调用
        Stu.getStudentNameValueInfo("Derry is OK a");
    }
}

66、注解@JvmField与Kotlin

// TODO 132.注解@JvmField与Kotlin
class Person {
    @JvmField
    val names = listOf("Zhangsan", "Lisi", "Wangwu")
}

/* 背后的原理代码:

    public final class Person{

        @NotNull
        private final List names = CollectionsKt.listOf(new String[]{"Zhangsan", "Lisi", "Wangwu"});

        // val 只读的,只有 getNames
        public final List getNames() {
            return this.names;
        }
    }



    @JvmField 背后会剔除私有代码 成员
    public final class Person {
       @JvmField
       @NotNull
       public final List names = CollectionsKt.listOf(new String[]{"Zhangsan", "Lisi", "Wangwu"});
    }
 */
public class KtBase132 {

    public static void main(String[] args) {
        Person person = new Person();
       //加上JvmField 可以直接调用属性
        for (String name : person.names) {
            System.out.println(name);
        }
    }
}

67、注解@JvmOverloads与Kotlin

//kotlin
// 默认参数
fun show( name : String, age : Int = 20, sex : Char = 'M') {
    println("name:$name, age:$age, sex:$sex")
}

// 默认参数
@JvmOverloads // 原理:编译器环节 专门重载一个函数,专门给 Java用
fun toast( name : String, sex : Char = 'M') {
    println("name:$name, sex:$sex")
}

// TODO 133-注解@JvmOverloads与Kotlin

fun main() {
    // KT端
    show("张三")
    toast("李四")
}
//java
public class KtBase133 {

    public static void main(String[] args) {
        // Java端
        // KtBase133Kt.show("张三") // Java无法享用 KT的默认参数

        KtBase133Kt.toast("张三"); // 相当于 Java 享用 KT的默认参数
    }
}

68、注解@JvmStatic与Kotlin关系

class MyObject {

    companion object {

        @JvmField
        val TARGET = "黄石公园"

        @JvmStatic
        fun showAction(name: String) = println("$name 要去 $TARGET 玩")
    }

}

// TODO 134-注解@JvmStatic与Kotlin关系
fun main() {
    // KT 端
    MyObject.TARGET

    MyObject.showAction("Derry")
}
public class KtBase134 {

    public static void main(String[] args) {
        // Java 端
        //加上@JvmField,java可以直接调用成员变量属性
        System.out.println(MyObject.TARGET);
       //加上@JvmStatic,java可以直接调用函数
        MyObject.showAction("Kevin");
    }
}

69、

相关文章

网友评论

      本文标题:Kotlin知识总结:

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