Kotlin进阶学习4

写在前面

本文接上文:Kotlin进阶学习3。上次文章主要学习了泛型的一些基本用法,这次来学习一下泛型的进阶用法。这部分还是有很大的难度的,勉强记录一下。

泛型的实化

介绍

泛型实化这个概念,其实对于学Java的很陌生。这里得先解释一下Java的泛型擦除机制。Java的泛型功能是通过类型擦除机制来实现的。就是说泛型对于类型的约束只在编译时期存在,运行的时候仍然按照JDK1.5之前的机制(即无泛型),JVM是识别不出来我们在代码中指定的泛型类型的。也就是说比如我们创建了一个List,虽然我们在编译约束我们必须输入String类型,但在运行时期只能识别出来他是个List,并不知道他的包含哪种类型。

所有基于JVM的语言,泛型功能都是基于类型擦除实现的。其中自然包括了Kotlin,因此我们无法使用T::class.java这样的语法,因为T的实际类型在运行的时候已经没了。

但Kotlin有一个内联函数的概念,这也就意味着Kotlin中是可以将内联函数中的泛型进行实化的。

使用

要使用泛型实化,首先必须是内联函数,其次要在声明泛型的地方加上reified关键字来表示该泛型要进行实化:

inline fun <reified T> getGenericType(){}

既然泛型实化了,那么就可以实现Java中不可能实现的一些功能了:

inline fun <reified T> getGenericType() = T::class.java

测试代码:

fun main(){
    val result1 = getGenericType<String>()
    println("result1 is $result1")
}

可以看到,我们实现了一个不可思议的功能。可以获得类型了。

应用

我们可以使用泛型实化对安卓中的一些操作进行优化,比如启动activity的操作:

val intent = Intent(context,TestActivity::class.java)
context.startActivity(intent)

我们新建一个kt文件:

inline fun <reified T> startActivity(context:Context){
    val intent = Intent(context,T::class.java)
    context.startActivity(intent)
}

这里我们定义了一个方法,里面实现了Activity的启动。这样我们要写启动activity时,就十分简单了:

startActivity<TestActivity>(context)

但这样似乎不能实现intent附加参数的用法了。我们可以改一下代码:

inline fun <reified T> startActivity(context:Context,block:Intent.() -> Unit){
    val intent = Intent(context,T::class.java)
    intent.block()
    context.startActivity(intent)
}

这里我们使用了高阶函数,定义了一个在Intent类里的拓展方法,这样就可以实现传入值的做法了:

startActivity<TestActivity>(context){
    putExtra("param1","data")
    putExtra("param2",123)
}

这样看来,这种写法要比之前的写法要看起来舒服的多。

泛型的协变和逆变

这方面的内容我看了好几遍书,愣是没看懂。先占个坑,等看懂了再来继续写。当然也可能不更新了,毕竟这两个特性并不是很常用。

委托

介绍

委托是一种设计模式。它的基本理念是操作对象自己不会去处理某段逻辑,而是委托给另外一个辅助对象去处理。Kotlin中也是支持支持委托功能的,分为类委托和委托属性。我们分条学习:

类委托

类委托的核心思想在于将一个类的具体实现委托给另外一个类去完成。我们都知道Set这种数据结构,它是一个接口,使用时要调用他的实现类,比如HashSet。而借助委托模式我们可以轻松实现一个自己的实现类:

class MySet<T>(val helperSet:HashSet<T>): Set<t> by helperSet{}

其中by是Kotlin中委托使用的关键字。这样子声明后,当我们需要对某个方法重新实现的时候,只需要单独重写那一个方法就可以了。类委托可以让我们免去重写那些大量重复的模版代码,而只专注于自己的方法或者重写需要重写的方法。

委托属性

委托属性的核心思想在于将一个属性(字段)的具体实现委托给另一个类去完成,比如:

class MyClass{
    var p by Delegate()
}

这样的写法,意味着将p属性的具体实现交给了Delegate类去完成,当调用p属性的时候自动调用Delegate类的getValue()方法,当赋值的时候自动调用Delegate类的setValue()方法。因此,我们也得实现Delegate类才行:

class Delegate{
    var propValue:Any? = null
    operator fun getValue(myClass:MyClass,prop:KProperty<*>):Any?{
        return propValue
    }
    operator fun setValue(myClass:MyClass,prop:KProperty<*>,value:Any?){
        propValue = value
    }
}

这是一种标准的代码实现模版。在Delegate类中必须实现getValue()和setValue()方法,且必须都要使用operator关键字进行声明。

在方法上,出现了一个KProperty<*>,它是Kotlin中的一个属性操作类,可用于获取各种属性相关的值。虽然在这用不着,但必须加上声明。<*****>代表你不知道或不关心泛型的具体类型,只是为了通过语法编译而已。

实际上,有一种情况也可以不用在Delegate类中实现setValue()方法,那就是MyClass中的p属性是使用val关键字声明的。也很好理解,val关键字是无法在初始化后被赋值的,自然也就不需要实现setValue()方法了。

总结

本次学习的内容有点少,因为Kotlin的知识学习的也差不多了。接下来会尝试记录下协程的相关内容,协程作为Kotlin中很有特色的一个功能,内容很多。就不在这里展开了。总的来说,这里学习了Kotlin中的泛型的一些高级特性,补充了委托的相关内容。实际上这都是一些简单的笔记,具体的使用还是要在实际开发中应用。

原文地址:https://www.cnblogs.com/wushenjiang/p/13479530.html