Kotlin 知识

Kotlin 小细节记录(6)

2022-02-25  本文已影响0人  zcwfeng

100-Kotlin语言的接口定义
101-Kotlin语言的接口的默认实现
102-Kotlin语言的抽象类学习
103-Kotlin语言的定义泛型类
104-Kotlin语言的泛型函数学习
105-Kotlin语言的泛型变换实战
106-Kotlin语言的泛型类型约束学习
107-Kotlin语言的vararg关键字(动态参数)
108-Kotlin语言的[ ]操作符学习
109-Kotlin语言的out-协变学习
110-Kotlin语言的in-逆变学习
111-Kotlin语言中使用in和out
112-Kotlin语言的reified关键字学习
113-Kotlin语言的定义扩展函数学习
114-Kotlin语言的超类上定义扩展函数
115-Kotlin语言的泛型扩展函数
116-Kotlin语言的标准函数与泛型扩展函数
117-Kotlin语言的扩展属性
118-Kotlin语言的可空类型扩展函数
119-Kotlin语言的infix关键字
120-Kotlin语言的定义扩展文件
121-Kotlin语言的重命名扩展学习
122-Kotlin语言的apply函数详解
123-Kotlin语言的DSL学习
124-Kotlin语言的变换函数-map
125-Kotlin语言的变换函数-flatMap
126-Kotlin语言的过滤函数-filter
127-Kotlin语言的合并函数-zip
128-Kotlin语言中使用函数式编程
129-Kotlin语言的互操作性与可空性
130-Kotlin语言的单例模式
131-注解@JvmName与Kotlin
132-注解@JvmField与Kotlin
133-注解@JvmOverloads与Kotlin
134-注解@JvmStatic与Kotlin关系
135-手写事件变换操作符之create
136-手写事件变换操作符之中转站
137-手写事件变换操作符之map
138-手写事件变换操作符之总结与简化代码
139-手写事件变换操作符之observer
140-手写事件变换操作符之Rx操作符总结


interface

interface TUSB{
    var usbVersion:String
    var usbDevice:String
    fun insertUsb():String
}

class Mouse():TUSB{
    override var usbVersion: String=""
        get() = "USB 3.0"
        set(value) {
            field = value
        }
    override var usbDevice: String=""
        get() {
            println("获取了${field} 的值")
            return field
        }
        set(value) {
            field = value
            println("设置了 ${field} 的值")

        }
    override fun insertUsb(): String {
       return "Mouse ${usbVersion},${usbDevice}"
    }
}

class KeyBoard(override var usbVersion: String, override var usbDevice: String):TUSB{
    override fun insertUsb(): String {
       return "KeyBoard ${usbVersion},${usbDevice}"
    }

}

fun main() {
    val usb1:TUSB = Mouse()
    usb1.usbVersion = "USB 3.1"
    usb1.usbDevice = "AAA"
    println(usb1.insertUsb())

    val usb2:TUSB = KeyBoard("USB 3.0","Keyboard")
    println(usb2.insertUsb())
}

1.接口里面的所有成员 和 接口本身 都是 public open 的,所以不需要open,这个是接口的特殊
2.接口不能有主构造
3.实现类不仅仅要重写接口的函数,也要重写 接口的成员
4.接口实现代码区域,全部都要增加 override 关键字来修饰


abstract
demo

abstract class BaseActivity{
    fun onCreate(){
        setContentView(getLayout());
        initView()
        initData()
    }

    abstract fun getLayout():Int
    private fun setContentView(id:Int) = println("setContentView ${id}...")
    abstract fun initView()
    abstract fun initData()

}

class MainActivity(): BaseActivity() {
    override fun getLayout(): Int {
        println("R.layout.main")
        return 1111
    }

    override fun initView() {
        println("Main initView")
    }

    override fun initData() {
        println("Main initData")
    }
    fun show() = super.onCreate()

}

fun main() {
    MainActivity().show()
}

泛型

class OutShow<T>(val obj:T){
    fun show() = println("$obj")
}

data class Stu(val name:String,val age:Int)
data class Teacher(val name:String,val age:Int)

fun main() {
    OutShow(Stu("zhangsan",16)).show()
    OutShow(Stu("zcwfeng",36)).show()
    OutShow(String("Hello world".toByteArray())).show()
}
fun <B> showme(obj:B){
    val r= obj?.also {
        println("it is $obj")
    }?:  println("it is null...")
}

    showme(Stu("zhangsan",16))
    showme(null)

Map 转换,(模仿RxJava操作符)

class MapClass<T>(val isMap: Boolean = false, val input: T) {
    inline fun <R> map(mapAction: (T) -> R): R? = mapAction(input).takeIf { isMap }
}

inline fun  <I,O> map(inputValue: I, isMap: Boolean = true, mapAction: (I) -> O): O? {
    return if (isMap) mapAction(inputValue) else null
}

fun main() {
    val test: String? = MapClass(isMap = true, 2222).map {
        it.toString()
    }
    val test2: Int? = MapClass(isMap = true, 2222).map {
        it
    }
    val teacher: Teacher? = MapClass(isMap = true, Stu("zcwfeng", 22)).map {
        Teacher(it.name, it.age)
    }
    println(test)
    println(teacher is Teacher)
    //map 仿 RxJava 变换
    val result = map(123){
        it.toString()
        "map wrapper${it}"
    }
    println(result)
}

泛型限定

open class MyAnyClass(name:String)
open class PersonClass(name: String):MyAnyClass(name)
class StudentClass(name: String):PersonClass(name)
class TeacherClass(name: String):PersonClass(name)
class DogClass(name: String)

// java T extends PersonClass
class PResultClass<T/*:PersonClass*/> (val inputValue:T,var isR:Boolean = true){
    fun getObj() = inputValue.takeIf { isR }
}

fun main() {
    val myAny = PResultClass(MyAnyClass("zcwfeng")).getObj()
    val per = PResultClass(PersonClass("zcwfeng")).getObj()
    val teacher = PResultClass(TeacherClass("zcwfeng")).getObj()
    val stu = PResultClass(StudentClass("zcwfeng")).getObj()
    val dog = PResultClass(DogClass("zcwfeng")).getObj()
    println("myAny=${myAny},\nper=${per},\nteacher=${teacher},\nstu=${stu},\ndog=$dog")
}

vararg关键字(动态参数)

class T11<T>(vararg objects: T, val isMap: Boolean = true) {
    // out 不能修改只能读取
    val objectArray: Array<out T> = objects

    // index 下对应的对象
    fun showObj(index: Int): T? = objectArray[index].takeIf { isMap }

    //
    fun <O> mapObj(index: Int, mapAction: (T?) -> O): O? = mapAction(objectArray[index].takeIf { isMap })
}

fun main() {
    // 真实数据类型 {Comparable<*> & java.io.Serializable}
    val values = T11("zwfeng", false, 12345, 12345.66, null, 'C', isMap = true)
    for (i in 0..5) {
        println(values.showObj(i))
    }

    println()

    val r1 = values.mapObj(0){
        it
        it.toString()
        it.toString().length
    }
    println("第零个元素的字符串长度是:$r1")

    val r2:String? = values.mapObj(2){
        "第三个元素$it"
    }
    println(r2)

    val p2 : T11<String> = T11("AAA", "BBB", "CCC", isMap = true)
    val r3 = p2.mapObj(0){
        it
        it.toString()
        "String? 类型的 $it"
    }
    println(r3)

}

获取不方便只能get(index),进行一个操作符重栽使用xxx[index],并且列出返回类型所有可能

class T13<INPUT>(vararg objects: INPUT, val isR: Boolean = true) {
    private val objarray: Array<out INPUT> = objects
    fun getR1(): Array<out INPUT>? = objarray.takeIf { isR }
    fun getR2(): Any = objarray.takeIf { isR } ?: "you null"
    fun getR3(): Any? = objarray.takeIf { isR } ?: null
    fun getR4(index: Int): INPUT? = objarray[index].takeIf { isR } ?: null
    fun getR5(index: Int): Any? = objarray[index].takeIf { isR } ?: "AAAA"
    operator fun get(index: Int): INPUT? = objarray[index].takeIf { isR }
}

fun <INPUT> inputFun(value: INPUT) {
    println((value as String?)?.length)
}

fun main() {
    inputFun("aaaaa")
    inputFun(null)
    val t = T13("aa","bb","cc","dd",null)
    println(t[1])
    println(t[3])
    println(t[4])
}

out-协变,in-逆变

interface Producer<out T> {
    fun produce():T

//    fun consume(item:T)
}

interface Consumer<in T>{
//    fun produce():T

    fun consume(item:T)
}

interface  ProducerConsumer<T>{
    fun produce():T

    fun consume(item:T)
}

  1. 协变 [out T 此泛型能够被获取 读取 所以是out]
  2. 逆变 [in T 此泛型只能被修改 更新 所以是in]
    没有进行out 和 in 限制的借口,没有限制
open class Animal // 动物
open class Humanity : Animal() // 人类
open class Man : Humanity() // 男人
open class WoMan : Humanity() // 女人

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

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

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

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

fun main() {
    val p1 : Producer<Animal> = ProducerClass1()
    val p2 : Producer<Animal> = ProducerClass2() 
    val p3 : Producer<Animal> = ProducerClass3() 
    val p4 : Producer<Animal> = ProducerClass4() 
}

  1. 去掉 out T ProducerClass1他本来就是 传递 Animal ,当然是可以的
    ProducerClass2,ProducerClass3,ProducerClass4,因为out, 才是被允许的

泛型规则默认情况下是:泛型的子类对象 不可以赋值给 泛型的父类对象,泛型具体处的子类对象 不可以赋值给 泛型声明处的父类对象
out: 泛型的子类对象 可以赋值给 泛型的父类对象
out: 泛型具体出的子类对象 可以赋值给 泛型声明处的父类对象
协变:父类 泛型声明处 可以接收 子类 泛型具体处

class ConsumerClass1 : Consumer<Animal> {
    override fun consume(item: Animal) {
        println("消费者 Animal")
    }
}

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

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

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

fun main() {
    val p1 : Consumer<Man> = ConsumerClass1() 
    val p2 : Consumer<WoMan> = ConsumerClass2() 
}
  1. ConsumerClass1,ConsumerClass2,因为in 才可以

默认情况下: 泛型具体实现处的父类 是不可以赋值给 泛型声明处的子类的
in:泛型具体出的父类 是可以赋值给 泛型声明处的子类的
逆变:子类 泛型声明处 可以接收 父类 泛型具体处
协变:out 父类 = 子类
逆变:in 子类 = 父类

    // CharSequence父类        String子类
    // 泛型默认情况下是:泛型的子类对象 不可以赋值给 泛型的父类对象
    //     List<CharSequence> list1 = new ArrayList<String>();
    List<? extends CharSequence> list2 = new ArrayList<String>();

    // 泛型默认情况下是:泛型的父类对象 不可以赋值给 泛型的子类对象
    // List<String> list3 = new ArrayList<CharSequence>();
    List<? super String> list4 = new ArrayList<CharSequence>();
  1. ? super T 就相当于 KT里面的in,所以才可以 泛型父类对象 赋值给 泛型子类对象
    ? extends T 就相当于 KT里面的out,所以才可以 泛型子类对象 赋值给 泛型父类对象

reifield
通过一个例子:默认随机输出一个对象,如果此对象和用户指定的对象不一致,我们就启用备用对象,否则就直接返回对象

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)

inline fun <reified T> randomOrDefault(defaultAction: () -> T): T? {
    val objList: List<Any> = listOf(
        ObjectClass1("obj1 李四", 22, "学习C"),
        ObjectClass2("obj2 王五", 23, "学习C++"),
        ObjectClass3("obj3 赵六", 24, "学习C#")
    )

    val randomObj = objList.shuffled().first()
    println("您随机产生的对象 幸运儿是:$randomObj")
    return randomObj.takeIf { it is T } as T?
        ?: defaultAction()
}

fun main() {
    val finalResult = randomOrDefault<ObjectClass1> {
        println("由于随机产生的对象 和 我们指定的ObjectClass1不一致,所以启用备用对象")
        ObjectClass1("备用 obj1 李四", 22, "学习C") // 最后一行的返回
    }
    println("客户端最终结果:$finalResult")

}

reified 前提必须是inline函数
泛型it is T判断必须是 reified 控制才可使用

扩展函数-扩展属性

fun String.addAction(number:Int) = this + "@".repeat(number)
fun String.showstr() = print(this)

fun main() {
    "zcwfeng".addAction(3).showstr()
}

超类扩展,链式调用扩展

data class ResponseData(val name:String,val age:Int)

fun Any.showContentPrint() = println("扩展内容 $this")
fun Any.showContentPrint2():Any{
    println("扩展内容2 $this")
    return this
}

fun main() {
    "zcwfeng".showContentPrint()
    123.4.showContentPrint()
    ResponseData("aaa",111).showContentPrint().showContentPrint()
    ResponseData("aaa",111).showContentPrint().showContentPrint2()
    ResponseData("aaa",111).showContentPrint2().showContentPrint2()
}

泛型扩展函数

fun <T> T.showContent() = println(if (this is String) "字符串类型:length$length" else "非String,内容:$this" )
fun <T> T.showCallTime() = println("call time:${System.currentTimeMillis()}")
fun test(){}
...

fun main() {
    "zcwfeng".showContent()
    123.4.showContent()
    ResponseData("aaa",111).showContent()
    test().showContent().showCallTime()
...
}

查看模拟官方扩展函数原理

let 内置函数

private inline fun <I,O> I.mLet(lambda:(I)->O) = lambda(this)

调用

val a:String = "".mLet {
        "aaa"
        false
        "de"
        it
    }

最后一行返回是本身,持有it,高阶函数用inline 优化lambda
系统内置函数
also,apply,let,run,with

扩展属性,

val String.myInfo: String
    get() = "调用时间${System.currentTimeMillis()},当前内容$this,长度 $length"
测试扩展属性,扩展函数辅助:
 "demo".myInfo.showstr()

可空类型扩展 String 和 String?是不一样的

fun String?.outputStringValue() = println(this ?: "null")
fun String?.outputStringValue2():String? = this

infix 中缀表达式

private infix fun<C,D> C.go(c:D){
    println("第一个内容$this")
    println("第二个内容$c")
}

    "aaa".go("bbbbb")
    "aaa" go "bbbbbb"

借鉴C++的一种简略语法中缀表达式
  1. 必须配合函数扩展使用
  2. 需要传递参数

扩展文件

// 添加一种能力,扩展文件,扩平台和应用
// Demo Use
// Java --> ExtOptKt.randomItemValue(mFragments);
// kotlin --->list.randowmIemValue()
public fun<E> Iterable<E>.randomItemValue() = println(this.shuffled().first())

// 使用对比
val list = listOf("张三","zcwfeng","David")
    val set = setOf(112.33,3333,4444)
    println(list.shuffled().first())
    println(set.shuffled().first())

    println(list.randomItemValue())

工具类放在一个扩展文件,这样这个类所有项目都可以用

可以重命名扩展,小技巧

import s5.ext.randomItemValue as itemRandom
// randomItemValue 可以用 itemRandom 代替
println(list.itemRandom())

apply 原理

private inline fun <INPUT> INPUT.mApply(lambda: INPUT.() -> Unit):INPUT {
//    lambda(this)
    lambda()
    return this
}

lambda: INPUT.() -> Unit 目的是让我们的扩展函数mApply 持有this,永远返回本身,支持链式调用

DSL-Domain Special Language

class Context {
    val info = "我是 zcwfeng DSL"
    val name = "DDDD"
    fun toast(str:String) = println("str is:$str")
}
inline fun Context.apply5(lambda:Context.(String)->Unit):Context{
    lambda(info)
    return this
}
fun main() {
    val context = Context().apply5 {
        println("it is $it,this is $this")
        toast("aaaa")
        toast(it)
        toast(name)
    }
    println(context)
}

小DSL语法:定义输入输出

  1. 定义lambda规则,输入必须是Context这个类,才能调用apply5,同事持有it和this
  2. 定义lambda规则,输出必须是Context这个类

在看一个例子

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

val file =  File("/Users/zcwfeng/Downloads/weimiao.html").applyFile { a, b ->
        println("路径$a,内容:$b")
        true
    }.applyFile { s, d ->  }
    println("file:$file")

map,flatMap

 val list = listOf("aa","bb","cc")
    val list2 = list.map {
        "[$it]"
    }.map {
        "[$it,文字长度:${it.length}]"
    }
    println(list2)
 val list = listOf("aa","bb","cc")
    val list2 = list.map {
        "/$it/"
    }.map {
        "--$it---文字长度:${it.length}---"
    }.flatMap {
        println()
        listOf("$it 学习C++","$it 学习Java","$it 学习Kotlin")
    }
    println(list2)

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

filter

fun main() {
    val nameLists = listOf(
        listOf("黄晓明", "李连杰", "李小龙"),
        listOf("刘军", "李元霸", "刘明"),
        listOf("刘俊", "黄家驹", "黄飞鸿")
    )
    nameLists.map {
        println(it)
    }
    println()

    nameLists.flatMap {
        println(it)
        listOf("")
    }
    println()

    nameLists.flatMap { it ->
        it.filter {
            println("$it filter")
            true
        }
    }.map {
        println("$it ")
    }

    println()

    nameLists.map {
        it.filter {
//            false
            true
        }
    }.map {
        print("$it   ")
    }

    println()
    println()

    nameLists.flatMap {
        it.filter {
            true
//            false
        }
    }.map {
        println("$it   ")
    }

    println()

    nameLists.flatMap {
        it.filter {
            it.contains("黄")
        }
    }.map {
        println("$it   ")
    }
}

filter 原理:filter {true,false} true他会加入到新的集合 进行组装新集合 返回, 否则false,过滤掉,不加入,返回空集合

zip


fun main() {
    val names = listOf("zcwfeng","david","luna")
    val ages = listOf(11,22,33)

    val zip:List<Pair<String,Int>> = names.zip(ages)
    println(zip)
    println(zip.toMap())
    println(zip.toMutableList())
    println(zip.toMutableSet())

    zip.forEach{ it ->
        println("name->${it.first},age->${it.second}")
    }

    zip.toMap().forEach { (k, v) ->
        println("name->$k,age->$v")
    }

    zip.toMap().forEach{
        println("name->${it.key},age->${it.value}")
    }       

}

zip原理:就是把 第一个集合 和 第二个集合 合并起来,创建新的集合,并返回
对比RxJava操作符zip类似功能

Java 和 Kotlin的调用,注解

@file:JvmName("Stus")
package s5

//Java 调用测试
fun getStudentInfo(name:String) = println("$name is ok")

Java Call

    public static void main(String[] args) {
//        Test21Kt.getStudentInfo("zcwfeng");
        Stus.getStudentInfo("zcwfeng");
    }

@file:JvmName("Stus") 必须卸载package之前, 调用的时候编译器默认会更改名字 Test21Kt->Stus

class PersonTest{
    @JvmField
    val names = listOf("abc","eee","fff")
}

java Call

        PersonTest personTest = new PersonTest();
//        personTest.getNames();
        for (String name:personTest.names){
            System.out.println(name);
        }

@JvmField 修饰之后,java就可以直接访问names. 不必在使用getNames

fun show(msg:String,code:Int = 20,name:String = "abc"){
    println("show")
}

@JvmOverloads
fun toast(msg:String,code:Int = 20,name:String = "abc"){
    println("show")
}


// 不能和Kt一样用默认参数
//        Test22Kt.show("zcwfeng");
        Test22Kt.toast("zcwfeng");

@JvmOverloads 可以让java想kotlin一样可以调用默认参数的函数

class GoStudy{
    companion object{
        @JvmField
        val TARGET = "清华北大"

        @JvmStatic
        fun showAction() = println("我要 到 $TARGET 上学")

    }
}

//        System.out.println(GoStudy.Companion.getTARGET());
//        GoStudy.Companion.showAction();

        System.out.println(GoStudy.TARGET);
        GoStudy.showAction();

加上 @JvmField 和 @JvmStatic之前,只能像注释代码一样调用
加上之后,就可以和Kotlin一样调companion object了

Kotlin 模仿RxJava create操作符手动实现


// 模拟rxjava create,输入没有任何参数,输出万能类型,
inline fun <OUTPUT> create(action: () -> OUTPUT): RxJavaCoreClassObject<OUTPUT> = RxJavaCoreClassObject(action())


// 保存Object,信息是value====create最后一行信息的返回
class RxJavaCoreClassObject<T>(val value: T)

inline fun<T,O> RxJavaCoreClassObject<T>.map(mAction:T.()->O) = RxJavaCoreClassObject(mAction(value))

// 只需要把输入内容输出就行
inline fun<T>RxJavaCoreClassObject<T>.observer(observerAction:T.()->Unit) = observerAction(value)
fun main() {
    create {
        "derry"
        123
        true
        "AAAAA"
    }.map{
        "your value is $this"
    }.map {
        "[$this]"
    }.map {
        "@@$this@@"
    }.map {
        println(this)
    }
}

一个有意思的lambda

 val fan: (String) -> (String) -> (Boolean) -> (Int) ->(String)-> Int = {
        {
            {
                {
                    {
                        99
                    }
                }
            }
        }
    }
    println(fan("AAA")("bbb")(false)(44)("aaaa"))
上一篇下一篇

猜你喜欢

热点阅读