Kotlin基础

自己整理的比较全面的kotlin基础
val和var和常量
1.var是可写的变量
2.val是只可读的变量
3.const val定义常量
range表达式
fun rangeTest(num:Int):Unit{
        if(num in 1..10){
            println("在1-10范围内")
        }else if(num in 11..30){
            println("在11-30范围内")
        }
    }
when表达式
 fun whenTest(num: Int):String{
        return when(num){
            1->{
                "是1";
            }
            2->{
                "是1";
            }
            else ->{
                "错误"
            }
        }
    }
string模板
fun defaultValue(name:String,age:Int = 50){
        println("name${name}----age${age}");

    }

函数定义
    fun funTest(name:String,age:Int = 30){

    }

    fun fTest(){
        funTest("name",20)
        funTest(name = "5555")
    }
NoString类型
 fun noThingTest(){
        TODO("我待会在来写好这个方法,运行会直接抛出异常")
    }
反引号中函数特点
1.用反引号可以把函数名包裹起来随意字符调用
fun main(){
    `测试函数##$$$%%^`("xxxxxxxxxx");
}

fun `测试函数##$$$%%^`(name:String){
    println("我是一个单引号测试函数")
}
2.方法调用,比如有个java类里面的方法是in()或者is(),在Kotlin中调用的话由于in和is在Kotlin中是关键字,所以调用的时候要用反引号包裹起来
 YinHan.`is()`调用 反引号包围起来
匿名函数 返回的永远是最后一行的结果
格式:
变量(){
    xxxx
}
val len = "我是一个字符串".count();
    println("长度${len}")
    //匿名函数
    val len2 = "我是一个字符串".count {
        it=='我'
    }

    print("len:${len}--len2:${len2}")
函数的类型&隐式返回
 /*函数类型*/
    /*函数声明---输入*/
    val methodAction :()->String;
    /*函数声明---输出*/
    methodAction = {
        "xxxxxxxx"
        //匿名函数不用写return 最后一行就是返回
    }
    /*函数声明---调用*/
    println(methodAction())
    
    等同于
    fun methodAction():String{
    return "xxxxxxxx";
}

带参数
 /*函数声明---输入*/
    val methodAction :(String)->String={
        //输出
        str->"xxxxxxxx"
        //匿名函数不用写return 最后一行就是返回
    }
    /*函数声明---调用*/
    println(methodAction("xxxx"))
it关键字
 //参数为一个的时候就有个默认的it
    var m:(String)->String = {
        //代表传递进来的参数
        it
    }
    m("xxxxxxxxxxxxxxxx");
匿名函数的类型推断
//    匿名函数的类型推断,可以不用写返回值类型,会自动推断,省略掉()->返回类型
    //如果函数的参数为null、也可以省略调
    val m2 ={
        //参数为null可以省略
        v1:Int,v2:String->
        "$v1 $v2"
    }
   println( m2(1,"xxxxxxxxxxx"))
函数作为参数
     //函数作为参数
    val m3:(String,String,(String,Int)->Unit)->String = {
        name,password,onResult->
        onResult("失败",200)
        "name:$name,password:$password"
    }

    //调用
     //    方法1
    m3("admin","1212",{
        msg:String,code:Int->
        println("code:$code,msg:$msg")
    })
//   方法2
    m3("admin","1230"){
        msg:String,code:Int->
        println("code:$code,msg:$msg")
    }

    等价于
    
fun m4(name:String,password:String,onResult:(String,Int)->Unit):String{
    onResult("失败",200)
    return "name:$name,password:$password"
}

内联 inline
//内联
//1.函数如果有lambad作为参数,就需要声明成内联inline
//2.如果不使用内联。在调用端,就会生成多个对象完成lambad的调用,会造成性能损耗
//3.使用了内联相当于c++中的#define宏定义,宏替换,会把代码替换到调用处,没有任何函数开辟,对象开辟的损耗
inline fun m4(name:String,password:String,onResult:(String,Int)->Unit):String{
    onResult("失败",200)
    return "name:$name,password:$password"
}
函数引用
函数作为参数来传递或变量赋值引用函数,使用::函数名
fun main(){
    //1.变量引用函数
    val f = ::funTest;
    f("函数引用",200);

    //2.做为函数参数
    funTest2("函数作为参数",f)
    funTest2("函数作为参数",::funTest)
}

fun funTest(msg:String,code:Int):Unit{
    print("msg:${msg},code:${code}")
}

fun funTest2(msg:String,onResult:(String,Int)->Unit){
    println("msh:${msg}")
    onResult("函数引用",200);
}

函数值作为返回值
//函数作为返回值
fun funTest3(msg:String):(String,Int)->String{
    println("msg:${msg}")
    //返回匿名函数
    return {
        name2:String,code:Int-> "xxxxxxxx"
    }
}


    var funTest3 = funTest3("xxx")("121", 200)
    println("funTest3:${funTest3}")
Kotlin语言的可空性特点
1.kotlin在初始化的时候默认不可以为null的
2.可以使用val name String? 来申明变量是可以为null的
3.如果变量可能为null的情况下。,可以使用变量?.方法来避免空指针
Kotlin中的let使用
let可以操作本身。他内部有个it就是本身,可以用let操作符来对变量本身做一些处理判断
fun letTest(){
    var name:String? = null;
    //name=‘’
    name = "";
    var name2 = name?.let {
        if(it.isBlank()){
            "默认值"
        }else{
            it
        }
    }
    println("name:${name2}")
}
非空断言的使用 !!
如果你能百分百确定一个变量不可能为null。就可以使用变量!!.属性来调用,不管变量是否为null都会执行
空合并操作符?:为null执行的操作
如果xx?:"为null就会执行"
如 var name:String?="xxx"; name = null;name?:"我是null的"
自定义异常处理
//自定义异常

fun funTest5(){
    try {
        var name:String?=null;
        //自定义异常处理
        checkException(name);
        val length = name!!.length;
    }catch (e:Exception){
        println("error:${e}")
    }
}

fun checkException(name: String?) {
    name?:throw MyException()
}

class MyException :RuntimeException("你的代码太垃圾了")

字符串截取 substring
//字符串截取
fun substringTest(){
    val msg = "I like Kotlin!";
    var indexOf = msg.indexOf("e")
    var substring = msg.substring(0, indexOf)
    //until 从0直到indexOf
    var substring2 = msg.substring(0 until indexOf)
}
字符串分割 split

//字符串分割
fun splitTest(){
    var msg = "A,B,C,D";
    //类型自动转换为List<String>了
    var split = msg.split(",")
    //解构 c++和kotlin都有 只有四个但是用了五个会报错
    var (v1,v2,v3,v4,v5) = split;
    print("v5:${v5}")
}
字符串的替换replace
//字符串的替换
fun replaceTest(){
    var msg = "lalalalwwwwfcfdsfsd";
    //可以些正则表达式也可以字符串
    var msg2 = msg.replace(Regex("[law]")){
        //it.value相当于没有替换
        it.value
        when(it.value){
            "l"->"0"
            "a"->"1"
            "w"->"2"
            else->it.value
        }
    }

}
字符串的遍历
/**
 * 字符串遍历
 */
fun strFor(){
    var msg = "lalalalwwwwfcfdsfsd";
    msg.forEach { 
        //默认有个it代表每一个字母
        println("$it")
    }
}
类型转换
/**
 * 字符串转int
 */
fun  strToInt(){
    //toInt字符串换int
    val num = "666".toInt();
    //这个时候会异常。字符串double类型无法转int
    val num2 = "666.66".toInt();
    //为了避免这种,可以使用toIntOrNull 异常就返回null
    val num3 = "666.33".toIntOrNull();
     //double转int
    var num4 = 6333.22.toInt();
    var num5 = 6333.22.roundToInt();//四舍五入
    var num6 = "0.2f".format(62.454)//保留两位小数
}
apply的使用
/**
 * apply的使用
 * 1.本身不包含it
 * 2.内部使用this始终代表调用的变量
 * 3.可以链式调用多次处理
 */
fun applyTest(){
    val msg = "xxxxxxxxxxxxxxxxxxx";
    //一般的匿名函数都会自带一个it 但是apply不带it,
    // 他带的是this。始终代表的是msg这个对象
    //所以可以apply链式调用
    msg.apply {
        println("长度:${this.length}")
    }.apply {
        println("最后一位:${this.substring(length-1)}")
    }
}
let内置函数的使用
/**
 * let内置表达式
 * 1.内置it包含的是调用本身
 * 2.返回值类型等于匿名函数最后一行的计算结果
 */
fun letTest2(){
    var msg = "xasadasdsad";
    val length = msg.let {
        //it表示的是msg本身
        println("msg$it")
        it.length;//返回的是msg的长度 int类型
    }
    println("msg的长度$length")

    //非空判断
    var m:String?=null;
    val m2= m?.let {
        println("m不是null")
        "为null"
    }?:"m是null的";
}
run内置函数的使用
run内含的是this本身。和apply是一致的,run每次返回的结果都是匿名函数的最后一行的结果,和let是一致的。相当于let和apply的合体
fun runTest(){
    val str = "我是一个字符串";
    var s = str.run {
        //内部是使用this,不是it 最后一句是返回
        this.substring(0,this.length-1)
    }.run { this.substring(0,this.length-1) }
     .run { this.substring(0,this.length-1) }
     .run { this.substring(0,this.length-1) }
     .run { this.substring(0,this.length-1) }
    println("$s") //打印 我是
}
with内置函数的使用
with作用是和run一样的。内含的是this本身,最后一句返回的是结果,但是使用方式不一样,with是一个方法,把变量传递到with里面去:
如 whith(str,::函数) 或者with(str){//处理操作}
fun withTest(){
    var str = "我们来演示使用with的使用方式";
    //具名函数
    var s:String =  with(str,::getStr)
    //匿名函数
    var length = with(s){
        //this
        length
    }
    with(length,::println)
}
also内置函数的使用
also的返回类型永远是他本身,和apply是一样的
also的匿名函数里面持有的是it,和let是一样的
fun alsoTest(){
    var str = "我们来使用also内置函数";
    str.also {
        //本身持有的是it
        //不管怎么操作,返回值都是str本身
        print("${it.length}")
    }
}

takeIf内置函数的使用
takeIf主要是判断结果是false还是true,false的hauler就返回null。true的话就返回本身,匿名函数中含it,一般配合空合并?:使用
fun takeifTest(){
    //takeIf 主要是判断true和false 如果为false 则返回为null
    val n = 10;
    var r = n.takeIf {
        //结果是false返回null 为true的话返回n本身
        n>6
    }
    println("$r")
    //一般takeIf配合空合并使用
    var result = n.takeIf {
        n>20
    }?:"n是小于20的"
    println("$result")
}
takeUnless内置函数使用
takeUnless和takeIf是相反的,takeUnless为true返回null,一般配合isNullOrBlank()使用

fun takeUnlessTest(){
    //takeUnless和takeIf是相反的
    //takeUnless为true返回null,为false返回本身
    //takeUnless一般配合isNullOrBlank使用
    var str:String? = null;

    val r = str.takeUnless {
        //it
        it.isNullOrBlank()
    }?:"str是null的"
    println("$r")
}
数组的使用 不可变
1.使用listOf来创建数组
2.使用list.[下标](不推荐使用,容易下标溢出)获取元素
3.使用getOrElse(下标){}来获取元素
4.使用getOrNull(下标)来获取元素
5.使用getOrNull+空合并来配合使用
fun listTest(){
    //使用listOf创建集合
    var list:List<String> = listOf("A","B","C");
    //普通方式获取值 使用下标
    var s = list[0]
    //使用下标获取很容易导致下标溢出导致崩溃
    var s2 = list[9999]
    //可以使用getOrElse(下标){匿名函数}
    var s3 = list.getOrElse(999){
        //下标溢出返回这个
        "下标溢出了哦"
    }
    //还可以使用getOrNull 下标不存在则返回null
    var s4 = list.getOrNull(9999)

    //一般getOrNull加上空合并一起使用
    var s5 = list.getOrNull(9999)?:"下标溢出了哦"
}
可变集合mutableListOf的使用
1.使用mutableListOf来创建
2.可以添加删除元素
3.使用toList()转换成不可变集合
4.使用toMutableList可以转换成可变集合
//可变集合
fun list2Test(){
    //可变集合使用mutableListOf
    var list:MutableList<String> = mutableListOf("A","B");
    //添加
    list.add("C")
    list.add(2,"D")
    //删除 根据下标
    list.removeAt(1)
    //删除元素
    list.remove("C");
    println("$list")
    //可变转换成不可变
    var list2 = list.toList();
    //不可变转换成可变
    var list3 = list2.toMutableList();
}
可变集合的mutator特性操作
1.可以使用+来添加元素
2.可以使用-来移除元素
fun mutatorTest(){
    val list:MutableList<String> = mutableListOf("A","B","C")
    //可以使用+添加元素
    list += "C"
    list += "D"
    //可以使用-移除元素
    list -= "A"

    //移除元素可以使用removeIf来过滤,为true就会移除
    list.removeIf{
        //移除掉包含A的元素
        it.contains("A")
    }
    println("$list");
}
集合的遍历
1.使用for(item in list)
2.使用forEach
3.使用forEachIndexed 带索引
//集合的遍历
fun list3(){
    var list:List<String> = listOf("A","B","C","D")

    //第一种遍历 in
    for(item in list){
       print("元素$item")
    }
    println()

    //第二种遍历 forEach
    list.forEach{
        print("元素:$it")
    }

    //第三种 带下标
    list.forEachIndexed(){
        index,item-> print("索引:$index,元素:$item")
    }
}
结构语法
//解构语法
fun list4(){
    val list:List<String> = listOf("A","B","C")
    //可以分别复制给v1 v2 v3
    val (v1,v2,v3) = list;
    println("$v1")

    //可以使用_来忽略不接受值
    val(_,_,v6) = list;
    print("$v6")
}
Set集合使用
1.set集合是不重复的
2.使用elementAt(下标)获取元素,容易下标溢出
3.使用elementAtOrElse来获取元素
4.使用elementAtOrNull来获取元素
5.使用elementAtOrNull+空合并
fun setTest(){
    //set不重复的集合
    val set:Set<String> = setOf("AAA","BBB","CCC");
    //获取元素
    set.elementAt(0);//这样很容易下标溢出
    set.elementAt(999);//下标溢出 程序崩溃
    //使用elementAtOrElse
    set.elementAtOrElse(0){"下标溢出啦"}
    set.elementAtOrElse(9999){"下标溢出啦"}
    //使用elementAtOrNull
    set.elementAtOrNull(0);//下标溢出就返回null
    //elementAtOrNull配合空合并使用
    set.elementAtOrNull(9990)?:"下标溢出"
}
可变Set
1.使用mutableSetOf来创建可变set
fun setTest2(){
    var set:MutableSet<String> = mutableSetOf("A","B");
    set.add("C")
    set.remove("A")
    set.forEach { 
        print("元素:$it")
    }
}

set和list的转换
1.可以使用toList把set转换list
2.可以使用toSet把list转换set
3.list可以使用distinct去重
//set和list转换
fun setToList(){
    var list:List<String> = listOf("A","B","C")
    //list转set 去重
    var set:Set<String> = list.toSet()
    //set在转list
    var list2 = set.toList()
    //可以使用distinct去重
    list2.distinct()
}
array数组使用

//数组
fun arrayTest(){
    var intArr = intArrayOf(1,2,3,4,5)
    var doubleArr  = doubleArrayOf(1.2,3.4,5.6)
    var longArr = longArrayOf(2.33.toLong(),6.33.toLong(),5.444.toLong())
    var shortArray = shortArrayOf(1,2,3,6)
    var charArr = charArrayOf('a','b','c')
    var floatArr = floatArrayOf(1.2f,5.6f)
    var booleanArr = booleanArrayOf(false,false,true)
    //可以存放对象
    var objectArr = arrayOf("",2,6.55.toLong())

    //array转list
    var toList = intArr.toList()
    //list转array
    var toIntArray = toList.toIntArray()
    //下标取值
    intArr[0]//容易下标溢出
    //使用elementAtOrElse 避免下标溢出
    intArr.elementAtOrElse(0){1}
    //使用elementAtOrNull来获取 下标溢出就为null
    intArr.elementAtOrNull(0)
}
map的创建
1.key to value
2.使用Pair(key,value)
//map
fun mapTest(){
    //map的创建
    var map:Map<String,Int> = mapOf("k1" to 11,"k2" to 22);
    //map的创建
    var map2:Map<String,Int> = mapOf(Pair("K1",22),Pair("K2",33))
}
map获取值
   //map的值获取 使用[] 没有找到返回null
    var k1 = map["k1"]
    //使用get来获取 和[]是一样的
    var k2 = map.get("k1");
    //getOrDefault没有找到返回默认值
    map.getOrDefault("k1",-1)
    //使用getOrElse 没有找到返回-1
    map.getOrElse("k1"){-1}
    //使用getValue 尽量避免 会导致崩溃
    map.getValue("k1")
map的遍历
//map的遍历
fun mapTest2(){
    var map:Map<String,Int> = mapOf(Pair("key1",22), Pair("key2",33));
    //遍历1
    map.forEach{
        //内置it
        print("${it.key}---${it.value}")
    }
    //遍历2
    map.forEach {
        key: String, value:Int ->
        print("${key}---${value}")
    }

    //遍历3
    map.forEach{(k,v)->  print("${k}---${v}")}

    //遍历4
    for(item in map){
        println("${item.key}---${item.value}")
    }
}
可变map
1.可以使用mutableMapOf创建可变map
2.可以使用+=添加元素
3.可以使用getOrPut获取元素,不存在则添加
//可变集合
fun map3(){
    val map:MutableMap<String,Int> = mutableMapOf();
    map += "key1" to 12
    map += Pair("key2",22)
    map.put("12",55)
    //2.获取的时候可以使用getOrPut 如果key不存在则会先把22放进map然后在get返回
    map.getOrPut("key3"){22}
}
类的创建和get set
1.类的创建
2.自带的get和set
3.field表示的就是当前字段的本身
//类的定义
class User{
   var name = "aaaa"
    //默认有一个get()和set(value)方法
    get()=field//默认返回 field表示的就是name本身
    set(value){
        field = value
    }
}

fun main(){
    var u = User();//创建对象
    u.name = "bbbbb";//获取对象的属性
    print("${u.name}")
}
计算属性和防范竞态条件
1.val申明的变量是只读的没有set方法
2.当对一个变量进行调用的时候这个变量可能为null,就必须采用防范竞态条件。是KT的规范
fun getUserInfo(str:String?):String{
    //当你调用这个成员的时候。可能为null,就必须采用防范竞态条件 这个是KT的规范
    return str?.let {
        if(it.isBlank()){
            "值是null的"
        }else{
            str
        }
    }?:"这个值是null的"
}
类的主构造函数(使用_xxx临时输入)
1.一般是用_xxxx作为临时输入类型,必须要成为变量后才可以直接使用
2.val 的变量没有set方法
3.set可以私有化 get不可以私有化
//类的构造函数
// _xxx都是临时输入类型。不可以直接调用 必须要成为变量才可以使用
class Dog(_name:String,_age:Int){

    //成为变量才可以使用
    var name = _name
        //get不可以私有化
        private get()=field
    val age = _age
        //私有化
       private get()=field
        //val 是没有set方法的
//        set(value){
//            field = value
//        }
    fun info(){
        //直接调用是不行的
        //println("$_name")
        println("$name")
    }
}
类的主构造函数(直接声明使用)
1.使用 val 变量名:类型 可以直接使用
//类的构造函数
//var name:String 其实内部相当于做了val name = _name
class Cat(var name:String,val age:Int){
    fun eat(){
        println("name:$name,age:$age")
    }
}
类的次构造函数
1.使用constructor关键字
2.次构造函数必须要实现主构造函数,因为主构造函数是统一管理,为了更好地设计
3.当调用次构造函数时候。先会调用主构造函数,然后才会执行次构造函数的代码
//类的次构造函数
class Fish(name:String){
    //次构造函数必须要调用主构造函数
    //因为主构造函数是统一管理,为了更好地设计
    //当调用次构造函数时候。先会调用主构造函数,然后才会执行次构造函数的代码
    constructor(name:String,age:Int):this(name){
        println("name:$name,age:$age")
    }
}
类构造函数的参数默认值
1.构造函数中的参数可以给默认值
2.有默认值的情况下,优先调用主构造函数
//构造函数中的参数默认值
class Tiger(name:String="大老虎"){
    //参数给默认值
    constructor(name:String="小老虎",age:Int=20):this(name){
        println("name:$name,age:$age")
    }
}

fun main(){
    //次构造函数
    Tiger("小老虎",230);
    //参数有默认值的情况下优先调用的是主构造函数
    Tiger();
}
代码块 init
1.初始化代码块 关键字init{},作用不是java中的static {} 而是java中的{}代码块
2.在初始化的时候执行。一般做一些参数校验 初始化操作
3.require(false){lambda代码} 前面第一个参数为false就会执行带二个参数的lambda代码,一般做参数校验

//代码块 init
class Snake(name:String){
    /**
     * 1.这个不是java中的static{}
     * 2.类似java中的{}构造代码块
     * 3.初始化代码块 init关键字
     */
    init {
        println("初始化了,构造函数执行")
        //初始化代码块可以做一些参数校验
        //require 第一个参数为false 就会执行后面的lambda代码
        require(!name.isNullOrBlank()){
            throw RuntimeException("name不可以为null")
        }
    }

    constructor(name:String,age:Int):this(name){
        println("次构造函数执行")
    }
}

构造初始化顺序
1.先执行主构造函数
2.init代码块和变量初始化同时执行,谁在前面谁就先执行。
3.在执行次构造函数
延迟加载 lateinit
1.用到的地方在加载,需要手动调用初始化加载
2.可以使用::变量名.isInitialized来判断是否加载,避免崩溃
//延迟加载
class T1{
    //使用关键字lateinit 懒加载,用到才会去加载
    lateinit var name: String;

    fun loadRequest(){
        ///网络操作
        name = "xxxxxx";
    }

    fun getName(){
        //会直接崩溃 因为还没有对name进行赋值
        println("name:$name")
        //可以判断 ::属性名.isInitialized 来判断是否初始化了加载
        if(::name.isInitialized){
            println("已经初始化加载")
        }else{
            println("还没初始化加载呢")
        }
    }
}
懒加载 by lazy
1.lateinit是在使用的时候。手动初始化加载,在使用
2.by lazy是自动的懒加载,在需要的时候自动初始化加载使用
fun main(){
    //初始化的时候不会调用p方法
    val demo by lazy {
        p()
    }

    println("...........");
    //这里才会调用dmeo初始化调用p方法
    print(demo)
}
fun p(){
    print("使用的时候才初始化")
}
1.类的集成必须要用open修饰,转换中java默认是public final
fun main(){
    //初始化的时候不会调用p方法
    val demo by lazy {
        p()
    }

    println("...........");
    //这里才会调用dmeo初始化调用p方法
    print(demo)
}
fun p(){
    print("使用的时候才初始化")
}
类型转换和类型判断
1.用is判断类型 如 s is Student
2.用as转换 如 s as Student
var s:Student2 = Student2();
    if(s is Person2){
        (s as Person2).eat()
    }
Any超类
1.类是java的Object
2.所有的类都默认继承Any
3.默认实现了toString equals hashCode等
object 单例类
1.用object修饰的类为单例
2.没有主构造函数,私有化
3.object修饰的类既是类名也是单例的实现
4.init类相当于 static{}
//单例类 使用object修饰
//没有构造函数 主构造函数私有化被禁用
object Day87{

    var name:String = "单例模式name";

    fun printName(){
        println("name:$name")
    }

    //等价于 static {xxxx}
    //这里会创建单例的实现 INSTANCE = Day787()
    init{
        println("初始化....")
    }
}

fun main(){
    //使用object修饰的既是类名也是类的单例实现
    //内部实现等于内部创建了一个 final static Day87 INSTANCE
    println(Day87)
    //等价于Day87.INSTANCE.name
    println(Day87.name)

}
对象表达式
1.kt匿名对象的实现 objetc:对象名(){...}
2.kt具名对象的实现 class XX :YYY(){....}
3.kt实现kt的接口是有一种方式,object:接口名{...}
4.kt实现java的接口有两种方式。1.object:接口名{} 2.接口名{xxxx}
//对象表达式
open class Day88{
    open fun f1(){
        println("方法1")
    }
    open fun f2(){
        println("方法2")
    }
}

open interface RunnableImpl{
    fun run()
}
class Day88Impl : Day88() {
    override fun f1() {
        super.f1()
        println("重写方法1")
    }

    override fun f2() {
        super.f2()
        println("重写方法2")
    }
}

fun main(){
    //KT调用对象 匿名对象调用
    var d:Day88 = object : Day88() {
        override fun f1() {
            super.f1()
            println("重写方法1")
        }

        override fun f2() {
            println("重写方法2")
        }
    }
    d.f1()

    //KT调用对象 具名调用
    var d2 = Day88Impl();
    d2.f1()

    //KT调用接口只有一种方式 object:对象名(){...}
    var runnable:RunnableImpl = object:RunnableImpl{
        override fun run() {
            println("实现接口")
        }

    }
    runnable.run();

    //KT调用java的接口有两种方法 1.object:对象名(){...} 2.对象名{...}
    var r2:Runnable = object : Runnable{
        override fun run() {
            println("KT调用java的接口实现方式1")
        }
    }

    //2.接口名{....}
    var r3:Runnable =  Runnable{
        println("KT调用java的接口实现方式2")
    }
}

伴生对象 companion
1..KT中没有static静态,所有使用companion来代替static的功能
2.无论对象创建多少次,伴生对象都只会初始化一次,只会加载一次
//伴生对象
class Day89 {
    //类的伴生对象 使用关键词 companion,
    // kt中是没有static的 这个相当于 static的功能
    //内部的实现其实相 当于在Day89类中创建了一个
//    final static class Companion{
//        private final static String info = "伴生对象info";
//    }
    companion object{
        var info:String = "伴生对象info";
    }
}

fun main(){
    //1.KT中没有static静态,所有使用companion来代替static的功能
    //2.无论对象创建多少次,伴生对象都只会初始化一次,只会加载一次
    //3.伴生对象只会初始化一次
    println(Day89.info)
}
内部类和嵌套类
1.内部类必须要用inner修饰符修饰
2.内部类可以直接访问外部类的成员变量
3.嵌套类不可以直接访问外部类
4.内部类调用方式 外部类().内部类().xxx
5.嵌套类调用方式 外部类.嵌套类().xxx

class Body{
    var name:String? = null;
    //嵌套类
    //不可以直接调用外部类的成员
    class Header{
        var header:String = "头部";
        fun printHeader(){
            println("头部信息:$header")
        }
    }

    //内部类
    //可以直接调用外部类成员信息
    inner class Footer{
        var footer:String="底部";
        fun printFooter(){
            println("${name}-->底部信息$footer")
        }
    }
}

fun main(){
    //内部类调用
    Body().Footer().printFooter();
    //嵌套类调用
    Body.Header().printHeader();
}
data 数据类型
1.使用data修饰符修饰数据列。类是java中的havaBean,
2.普通列只是有set和get和构造方法。data类默认除了get和set,构造外、还从写了toString equals copy hashCode等方法
3.数据类不能使用abstract open selead inner等关键字
data class Result(var code:Int,var msg:String):Any()
copy函数
1.对象拷贝
2.内置的方法只会考虑主构造函数,不会执行次构造函数的代码,如copy不会执行次构造函数里面的代码。
data class Day92(var name:String,var age:Int){
    init {
        println("主构造函数执行")
    }
    constructor(name: String):this(name,20){
        println("次构造函数")
    }
}

fun main(){
    var d = Day92("XiaoA")
    var d2 = d.copy()
    println("d:$d")
    d2.age=30
    println("d2:$d2")

    println(d==d2)
}
解构申明
1.使用operator关键字申明解构,
2.必须使用component1开始申明
3.顺序必须和成员变量一一对应
class Day93(var name:String,var age:Int,var sex:Char) {
    //注意顺序 必须是component1 从1一次顺序开始 和成员顺序一一对应
    operator fun component1() = name;
    operator fun component2() = age;
    operator fun component3() = sex;
}

fun main(){
    //解构 可以一一对应对象的属性
    var (name,age,sex) = Day93("A",20,'a');
    var (_,age2,_) = Day93("B",20,'a');
}
重载运算法
1.可以使用operator fun 运算符(参数):返回类型{
    return xxx;
}
来重载运算符
//运算符重载
data class Day94(var num:Int){
    //plus代表+运算
    //可以使用operator fun Day94. 查看KT支持的所有重载运算符
    operator fun plus(num: Int):Day94{
        this.num +=num;
        return this;
    }
}

fun main(){
    println(Day94(20)+52) //Day94(num=72)
}
枚举
1.使用关键字enum calss 名{
    枚举值,
}
2.枚举值等于本身
//枚举
enum class Day95{
    星期一,
    星期二,
    星期三
}

fun main(){
    //枚举的值等于本身
    println(Day95.星期一)
    //枚举等于本身
    println(Day95.星期一 is Day95) //true
}
枚举的一般用法
1.枚举的参数必须和主构造函数参数一致
//身体信息
data class BodyInfo(var header:String,var height:Int){

}
enum class Day96(var body:BodyInfo){
    //枚举的主构造函数必须和枚举参数保持一致
    Man(BodyInfo("男人",20)),
    Woman(BodyInfo("女人",18));

    fun show(){
        println("头部:${this.body.header},高度:${this.body.height}")
    }

    fun update(body: BodyInfo){
        this.body = body;
        println("更新后${this.body}")
    }
}

fun main(){
    Day96.Man.show()
    Day96.Woman.show()
    Day96.Man.update(BodyInfo("xxx",50))
    Day96.Woman.update(BodyInfo("xxx",60))
}
密封类
1.密封类其实是枚举的扩展,可以展示不同的实例,
2.主要配合when来使用,可以容纳所有的条件
3.使用关键字sealed
//密封类
sealed class Ui{
    object show:Ui()
    object hide:Ui()
    class TranslateX(val x:Int):Ui()
    class TranslateY(val x:Int):Ui()
}

fun main(){
    var op:Ui = Ui.TranslateX(20);
    when(op){
        Ui.show-> println("显示组件")
        Ui.hide-> println("隐藏组件")
        is Ui.TranslateX-> println("偏移量x-->${op.x}")
        is Ui.TranslateY-> println("偏移量y-->${op.x}")
    }
}
接口的定义
1.使用关键字interface申明
2.接口不能有构造函数
3.实现接口必须要实现接口的成员以及方法
4.接口的成员和方法都默认加了open

//1.接口定义
//接口内的所有成员都默认加了open
//接口不能有主构造函数
//实现接口不仅要实现接口方法,还要实现接口成员
interface Usb{
    var name:String //usb名字
    fun insertUSB():Unit //usb插入
}

class Mouse(override var name: String="鼠标"):Usb{
    override fun insertUSB(): Unit {
        println("${name}插入了USB")
    }
}

class KeyBoard() :Usb{
    override var name: String = "键盘"
    set(value) {
        println("设置数据")
        field = value;
    }
    get() {
        println("获取数据")
        return field;
    }

    override fun insertUSB() {
        println("${name}插入了USB")
    }
}

fun main(){
    var m:Mouse = Mouse();
    m.insertUSB()

    var k:KeyBoard = KeyBoard()
    k.name = "键盘";
    k.insertUSB()
}
接口的默认实现
1.可以给接口的成员重写get方法来给成员默认值
2.接口的规范来说这样是不可以的
3.接口的val只读后面也是可以修改的
interface Usb{
    //必须得val
    val name:String //usb名字
    get() {return "一个默认值"}
    fun insertUSB():Unit //usb插入
}

抽象类
1.使用关键字abstract申明
2.抽象类可以有实现也可以有抽象方法
3.继承抽象类必须要实现所有的抽象方法
abstract class BaseActivity{
    fun onCreate(){
        getLayoutId()
        initView();
        initData();
        initXXX();
    }

    abstract fun getLayoutId():Int
    abstract fun initView()
    abstract fun initData()
    abstract fun initXXX()
}

class LoginActivity :BaseActivity(){
    override fun getLayoutId(): Int {
        println("获取布局ID")
        return 20;
    }

    override fun initView() {
        println("初始化View")
    }

    override fun initData() {
        println("初始化Data")
    }

    override fun initXXX() {
        println("初始化xxx")
    }

    fun show(){
        super.onCreate()
    }
}

fun main(){
    LoginActivity().show()
}
泛型类的使用
1.和java的泛型类很相似
//使用泛型类
class Day102<T>(val obj:T){
    fun show(){
        println("万能输出器:${obj}")
    }
}

data class Teacher2(var name:String,var age:Int)

fun main(){
    var t:Teacher2 = Teacher2("张三",20)
    Day102(t).show()
}
泛型方法
fun <A> show(item:A):A?{
   val r =  item?.apply {
        println(this)
        item
    }?:item
    return r
}
泛型实战之类型转换
1.类是rxjava的map操作符
2.可以将任意类型转换成其他任意类型

class Day103<T> (var isMap:Boolean,var input:T){

    fun <R> map(mapAction:(T)->R):R? = mapAction(input).takeIf { isMap }
    //两种是等价的
    fun <R> map2(mapAction:(T)->R): R {
        return mapAction(input)
    }
}


//高级一点写法
inline fun <I,R> map(input:I,mapAction: (I) -> R):R = mapAction(input)

fun main(){
    var d = Day103(true,12212)
    var r = d.map {
        it.toString()+"5555"
    }
    println(r)

    val r2 = map("95922323"){
        it.toInt()
    }
    println("$r2")
}

泛型类型限制
1.类是java中的T extends XXX类
2.只有限制类本身和它的子类可以使用
3.T:限制类

open class C1{}
open class C2:C1(){}
class C3:C2(){}

class C4<T:C2>(cls:T):C2(){
    fun show(){
        println("只有C2的子类以及本身可以访问这个")
    }
}

fun main(){
    val c1:C1 = C1();
    val c2:C2 = C2();
    val c3:C3 = C3();
    //泛型类型限制只有c2以及他的子类才可以调用
    var c4 = C4(c1)
    var c5 = C4(c2)
    var c6 = C4(c3)
}

不定参数 vararg
1.使用关键字申明vararg
//不定参数
class Day105(vararg var tags:Any){
    var data = tags;
    fun show(){
        for (item in data) println("参数:$item")
    }
}

fun main(){
    var d = Day105("12",12,-1)
    d.show()
}
out 协变
1.修饰的泛型只可以获取,不可以修改
2.修饰后的泛型子类可以赋值给泛型的父类
3.相当于java中的? extends T
4.父类=子类
//生产者
//out修饰的泛型只能输出不能修改
interface Produce<out C>{

    //这个时候就会报错。因为使用out标记的泛型不可以修改
//    fun updateConsumer(consumer:C){
//
//    }
    //可以获取泛型
    fun getConsumer():C;
}

class Produce1():Produce<Animal>{
    override fun getConsumer(): Animal {
        return Animal()
    }

}

class Produce2():Produce<Man>{
    override fun getConsumer(): Man {
        return Man()
    }

}

class Produce3():Produce<Woman>{
    override fun getConsumer(): Woman {
        return Woman()
    }

}


open class Animal{

}
//为Animal的子类
class Man:Animal(){

}
//为Animal的子类
class Woman:Animal(){

}

class Day109 {
    //不加out 不会报错
    var p1:Produce<Animal> = Produce1();
    //没有out会报错,因为 Produce2接受的泛型是Man但是使用Animal也可以。因为使用了out 相当与java中的 ? extends T
    var p2:Produce<Animal> = Produce2();
    //没有out会报错
    var p3:Produce<Animal> = Produce3();
        //泛型的默认情况下,泛型的子类对象不可以赋值给泛型的父类对象 比如Produce<Man>无法赋值给Produce<Animal>
        //out 关键字可以吧泛型的自子类对象赋值给泛型的父类对象
}
in 逆变
1.泛型中默认泛型父类不可以赋值给泛型子类
如 //这样写是错误的。泛型的父类对象不可以复制给泛型的子类对象
    //KT中使用in关键字修饰就可以泛型的父类对象可以赋值给泛型的子类对象
    List<String> list2 = new ArrayList<CharSequence>();
2.但是KT中使用in关键字,就可以泛型的父类对象赋值给泛型子类对象
3.子类=父类
interface Produce<in C>{


    fun updateConsumer(consumer:C){

    }
    //这里就会报错 in只能修改不可以输出
    fun getConsumer():C;
}

class Produce1():Produce<Animal>{
    override fun getConsumer(): Animal {
        return Animal()
    }

}

class Produce2():Produce<Man>{
    override fun getConsumer(): Man {
        return Man()
    }

}
class Produce3():Produce<Woman>{
    override fun getConsumer(): Woman {
        return Woman()
    }
}
open class Animal()
//为Animal的子类
class Man:Animal()
//为Animal的子类
class Woman:Animal();

class Day109 {

    //使用关键字in可以泛型的父类可以赋值给泛型的子类
    var p1:Produce<Man> = Produce1();
    var p2:Produce<Woman> = Produce1();
}
reified关键字
1.reified一般作用在泛型上,如果要使用is等和T做比较,就必须在泛型申明前面加上reified
2.使用reified一定要在方法前面加上inline关键字
3.实例化类型参数
//随机生成三个类。如果生成的类不等于用户规定的泛型类。那么就返回默认值
///申明三个data类
data class D1(var name:String)
data class D2(var name:String)
data class D3(var name:String)

class Day110 {
    //使用reified必须加上inline
    inline fun <reified T> randomClass(defaultAction:()->T):T?{
        val list = listOf<Any>(D1("D1"),D2("D2"),D3("D3"))
        var d:Any? = list.shuffled().first()
        //这里使用it is T 就必须加上reified关键字
        //这里使用后T?是如果it is T为false就返回null null去转换as T 就会报错 所以使用T?
        return d.takeIf { it is T } as T? ?:defaultAction()
    }

}

fun main(){
    val r = Day110().randomClass<D1>{
        D1("默认D1")
    }

    println(r)
}
扩展
1.Kotlin 可以对一个类的属性和方法进行扩展,且不需要继承或使用 Decorator 模式。
扩展是一种静态行为,对被扩展的类代码本身不会造成任何影响。
class Day115{
    var name:String="Day115"
}
//扩展函数里面可以访问扩展类的所有成员和方法
fun Day115.show(){
    println("我是Day115的扩展函数-->${name}")
}
fun main(){
    Day115().show()
}
泛型扩展
1.所有的对象和方法都是泛型
2.扩展泛型所有的对象都可以调用
3.扩展函数内部本身包含this
//泛型扩展类
//所有的类都是泛型 都可以使用
fun <T> T.out(){
    println("输出本身:$this")
}

fun <I> I.outTime(){
    println("调用时间:${Date().time}")
}

fun main(){
    //任何对象都可以调用
    "A".out();
    12.out();
    //支持链式调用
    "123".out().outTime()
}


泛型扩展的实例
1.let等原理
//let原理
//对泛型扩展 内部持有it 返回最后一行
private inline fun <I,O> I.mLet(label:(I)->O):O = label(this)
扩展属性

//扩展属性
var String.myInfo:String
    get()="xxxxxxxxxxxx"
    set(value) {

    }
    
    调用println("xxx".myInfo)
可空类型的扩展
//可空类型的判断
fun String?.info():String{
    if(this.isNullOrBlank()){
        return "默认值";
    }
    return this;
}

infix 终缀表式
1.可以简化代码 
2.必须要结合扩展使用
3.必须传递一个参数
//终缀表示式infix
//可以简化代码
//1.结合扩展使用
//2.必须要给定传递参数
//写法"yyyy".into(555) 可以简化 "xxxxxx" into 55
infix fun <C1,C2> C1.into(c:C2):C1{
    println("接受的参数${c}")
    println("this:$this")
    return this
}

fun  main(){
    val r = "xxxxxx" into 55

    "yyyy".into(555)
    println("r:$r")
}
扩展文件
1.扩展文件就是把一系列的扩展函数放在一个文件里面,其他地方导入包调用
重命名
1.有时候第三方的类名或者方法名太长了,可以使用as重命名
import com.l024.test.kotlin.Day105 as d105
apply的原理
1.apply始终返回的是本身
2.apply内部持有的是this
3.匿名函数持有this使用T.()->Unit这种方式
//1.apply始终返回的是本身
//2.apply内部持有this
//T.()->Unit是为了匿名函数持有一个this
fun <T> T.mApply(lambda:T.()->Unit):T{
    lambda()
    return this;
}

fun main(){
    "123".mApply {
        println("this:$this")
    }.mApply {
        println("")
    }
}
map扩展的使用
1.list.map可以将list中每一个item转换成其他类型。
2.返回是一个新的list
3.把每一个item(String等类型)加入一个新集合

//map的原理
inline fun <I,O> Iterable<I>.mMap(transform:(I)->O):List<O>{
    var list:MutableList<O> = mutableListOf<O>();
    for(item in this){
        list.add(transform(item))
    }
    return list
}


//map的使用
fun main(){
    var list:List<String> = listOf<String>("a","b","c")
    //map可以转换每一项item返回新的list
//    list.map{
//        //返回每一项
//        it.uppercase(Locale.getDefault())
//    }.map {
//        println("$it")
//    }

    list.mMap {
        it.uppercase(Locale.getDefault())
    }.mMap {
        println("$it")
    }
}
flatMap
1.和map差不多,但是flatMap是把每一个元素it转换成一个集合,返回的时候是一个List<List<String>> 内部最后会处理成一个List<String>返回
fun main(){
    var list:List<String> = listOf("A","B")

    //flatmap中是把item转换成一个list,然后返回List<List<String>> 最后处理成一个list返回
    var l = list.flatMap {
        //这里返回的是一个list
        listOf("$it--1","$it--2")
    }
    println(l)
    //结果 [A--1, A--2, B--1, B--2]
}
filter 过滤
1.一般配合flatMap使用
2.返回true就把元素添加到一个新的list返回

fun main(){
    var list:List<List<String>> = listOf(
        listOf<String>("A"),
        listOf<String>("B"),
        listOf<String>("C"),
    )

    //使用map来过滤
    val l = list.map {
        it.filter {
            it=="A"
        }
    }
    println("map-->过滤结果:$l")
    //map-->过滤结果:[[A], [], []]

    var l2 = list.flatMap {
        //filter为true就把元素新增到一个list中返回。为false就不添加
        it.filter {
            it=="A"
        }
    }
    println("flatMap-->过滤结果:$l2")
    //flatMap-->过滤结果:[A]
}
zip
1.把两个数组合并成一个数组
2.第一个数组的值为KEY
3.第二哥数组的值为value
4.返回的类型其实是List<Pair<K,V>>

fun main(){
    var list1:List<String> = listOf("A","B","C")
    var list2:List<Int> = listOf(1,2,3)

    //使用zip将两个list合并成一个
    //返回的是一个List<Pair<String,Int>>类型
    //zip把第一个数组的值当做K,第二个数组的值当做V
    var zip:List<Pair<String,Int>> = list1.zip(list2)
    println("zip:$zip")
    //zip:[(A, 1), (B, 2), (C, 3)]

    //遍历
    var toList = zip.toList()
    println("toList:$toList")
    //toList:[(A, 1), (B, 2), (C, 3)]

    var toMap = zip.toMap()
    println("toMap:$toMap")
    //toMap:{A=1, B=2, C=3}

    //遍历zip
    zip.forEach {
        //it 其实是一个Map.Entry<K,V>类型
        println("key:${it.first},value:${it.second}")
    }
    //普通方法
    zip.toMap().forEach(){k,v->{
        println("k:${k},v:${v}")
    }}
    //解构方法
    zip.toMap().forEach(){(k,v)->{
        println("k:${k},v:${v}")
    }}
}
单例模式 java&KT
1.饿汉式 开始就调用初始化
2.懒汉式 需要用的时候才会初始化
java版饿汉式
public class Day130Java {
    private static Day130Java instance = null;
    private Day130Java(){}
    static {
        instance = new Day130Java();
    }
    public static Day130Java getInstance(){
        return instance;
    }
}

Kt版饿汉式
object 类名{}

java版懒汉式
class Demo2{
    private static Demo2 instance = null;
    private Demo2(){}

    public static Demo2 getInstance(){
        if(instance==null){
            instance = new Demo2();
        }
        return instance;
    }
}

KT版懒汉式
class KtDemo1{
    companion object{
        private var instance:KtDemo1? = null
            get() {
                if(field==null){
                    field  = KtDemo1()
                }
                return field
            }

        fun getInstanceAction():KtDemo1{
            //两个!作用就是确定instance不为null
            return instance!!;
        }
    }

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

java版懒汉式 保证安全
//懒汉式 保证安全
class Demo3{
    private static Demo3 instance = null;
    private Demo3(){}

    public static Demo3 getInstance(){
       if(instance==null){
           synchronized (Demo3.class){
               if(instance==null){
                   instance = new Demo3();
               }
           }
       }
        return instance;
    }
}

KT版懒汉式 保证安全 使用by lazy
//懒汉式 保证安全
class  KtDemo2 private constructor(){
    companion object{
        private val instance:KtDemo2 by lazy(mode = LazyThreadSafetyMode.SYNCHRONIZED) {
            KtDemo2()
        }
    }
}

@flie:JvmName(“类名”)
1.这个注解可以在编译时期修改我们的类名
2.这样java在调用KT类的时候就比较方便
3.这个注解必须写在package的外面
@file:JvmName("xxx")
@JvmField注解
1.这个注解可以在java中直接通过类访问到成员变量
2.没有这个注解java中只能通过get属性名来访问成员变量
KT代码
class Day132 {
    @JvmField
    val list:List<String> = listOf("A","B")
}

java代码
public class Day132_ {
    public static void main(String[] args) {
        //没有加@JvmField注解
        //调用KT类
        Day132 day132 = new Day132();
        //这样直接调用变量是不行的
//        day132.list
        // 只能通过getList获取Kt类中的属性
        List<String> list = day132.getList();
        //加了注解@JvmField就可以直接调用
        List<String> list1 = day132.list;
    }
}

@JvmOverloads注解
1.java调用KT方法不支持默认参数形式
2.加了注解就可以使用KT方法的默认值
kt代码
//不加注解java调用就必须要两个参数,java不支持KT的默认参数
@JvmOverloads
fun funText(name:String="xxx",age:Int=20){

}

java的代码
  //加了注解就可以使用KT的默认参数
        Day132Kt.funText("xxxx");
@JvmStatic注解
1.java中调用KT静态方法都必须还得调用下内部类才可以调用
2.加了注解就可以直接调用
kt代码
class Day133 {
    companion object{
        fun show(){
            println("静态方法")
        }

        @JvmStatic
        fun show2(){
            println("静态方法")
        }
    }
}

java代码
public class Day133_ {
    public static void main(String[] args) {
        //调用KT的静态方法
        //必须点Companion然后才可以调用 因为KT原理中是生成了一个内部类
        Day133.Companion.show();
        //可以加上注解JvmStatic 就可以直接调用静态方法
        Day133.show2();
    }
}

实现RxJava基本原理
//rxjava的核心类
class RxjavaCore<T>(var value:T){

}
//RxJava的create
inline fun <OUTPUT> create(action:()->OUTPUT):RxjavaCore<OUTPUT>{
    return RxjavaCore<OUTPUT>(action())
}
//扩展RxJava的map
inline fun <I,O> RxjavaCore<I>.map(action: (I) ->O):RxjavaCore<O>{
    return RxjavaCore<O>(action(this.value))
}
//扩展RxJava的observer
inline fun <I> RxjavaCore<I>.observer(action: I.() -> Unit):Unit{
    action(this.value)
}
fun main(){
    create {
        "模仿Rxjava的Create方法"
    }.map {
        "RxJava中的map转换"
    }.map {
        100
    }.observer {
        println("RxJava的observer")
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Unknown world

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值