Kotlin学习手记--泛型泛型约束泛型型变星投影泛型擦除内联特化
Posted 川峰
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Kotlin学习手记--泛型泛型约束泛型型变星投影泛型擦除内联特化相关的知识,希望对你有一定的参考价值。
泛型约束:
fun <T : Comparable<T>> maxOf(a: T, b: T): T
return if (a > b) a else b
fun main()
val max = maxOf("Hello", "World")
println(max) //输出World
多个泛型参数,可以每个泛型都有约束:
fun <T, R> callMax(a: T, b: T): R
where T : Comparable<T>, T : () -> R, //T有两个约束
R : Number //R有一个约束
return if (a > b) a() else b()
类似的还有Map类,它的K 和V泛型都进行了约束:
class Map<K, V> where K : Serializable, V : Comparable<V>
协变:
简而言之就是用out
关键字修饰的泛型就是协变,协变有个继承的关系,比如Int是Number的子类,返回值为协变泛型类型的称为协变点。协变点主要是指输出的类型,用来生成某个实例(生产者)。
例子:
interface Book
interface EduBook : Book
class BookStore<out T : Book>
fun getBook(): T
TODO()
fun covariant()
val eduBookStore: BookStore<EduBook> = BookStore<EduBook>()
val bookStore: BookStore<Book> = eduBookStore
val book: Book = bookStore.getBook() //书店只能获取普通的书
val eduBook : EduBook = eduBookStore.getBook() //教辅书店只能获取教辅书籍
子类获取子类,父类获取父类,能提供子类的自然可以提供父类。
逆变:
简而言之就是用in
关键字修饰的泛型就是逆变,作为函数输入参数的泛型称为逆变点。逆变点主要是指输入的参数类型,是消费者。并且消费者的继承关系跟协变是相反的。
例子:
open class Waste
class DryWaste : Waste()
class Dustbin<in T : Waste>
fun put(t: T)
TODO()
fun contravariant()
val dustbin: Dustbin<Waste> = Dustbin<Waste>()
val dryWasteDustbin: Dustbin<DryWaste> = dustbin
val waste = Waste()
val dryWaste = DryWaste()
//普通垃圾桶可以放入任何垃圾
dustbin.put(waste)
dustbin.put(dryWaste)
//干垃圾桶只能放入干垃圾,不能放普通垃圾
// dryWasteDustbin.put(waste)
dryWasteDustbin.put(dryWaste)
星投影
星投影在所有逆变点的下限类型是Nothing, 因此不能用在属性或函数上
说白了只是一个描述符,可以简写泛型参数而已。
fun main()
val queryMap: QueryMap<*, *> = QueryMap<String, Int>()
queryMap.getKey()
queryMap.getValue()
val f: Function<*, *> = Function<Number, Any>()
//f.invoke()
if (f is Function)
(f as Function<Number, Any>).invoke(1, Any())
maxOf(1, 3)
HashMap<String, List<*>>()
//endregion
val hashMap: HashMap<*, *> = HashMap<String, Int>()
//hashMap.get()
class QueryMap<out K : CharSequence, out V : Any>
fun getKey(): K = TODO()
fun getValue(): V = TODO()
fun <T : Comparable<T>> maxOf(a: T, b: T): T
return if (a > b) a else b
class Function<in P1, in P2>
fun invoke(p1: P1, p2: P2) = Unit
泛型擦除(伪泛型)
Java与Kotlin实现机制一样,在运行时擦除真正的类型,C#则会真的生成一个类型去执行。
内联特化:
内联特化在调用的地方会替换到调用处,因此这时类型是确定的了,即已经特化成某个具体类型。通过fun前面的关键字 inline 和泛型参数T前面的 reified 参数两个来指定泛型参数在调用处实例化。
inline fun <reified T> genericMethod(t: T)
//val t = T()
val ts = Array<T>(3) TODO()
val jclass = T::class.java
val list = ArrayList<T>()
if(list is List<*>)
println(list.joinToString())
class Person(val age: Int, val name: String)
inline fun <reified T> Gson.fromJson(json: String): T = fromJson(json, T::class.java)
fun main()
val gson = Gson()
val person2: Person = gson.fromJson(""""age":18,"name":"Bennyhuo"""")
val person3 = gson.fromJson<Person>(""""age":18,"name":"Bennyhuo"""")
实例:模仿的Self Type
typealias OnConfirm = () -> Unit
typealias OnCancel = () -> Unit
private val EmptyFunction =
open class Notification(
val title: String,
val content: String
)
class ConfirmNotification(
title: String,
content: String,
val onConfirm: OnConfirm,
val onCancel: OnCancel
) : Notification(title, content)
interface SelfType<Self>
val self: Self
get() = this as Self //当前类型强转成Self类型
//泛型添加约束只能传子类
open class NotificationBuilder<Self: NotificationBuilder<Self>>: SelfType<Self>
protected var title: String = ""
protected var content: String = ""
fun title(title: String): Self
this.title = title
return self //返回接口的常量属性即可,运行时就是当前子类实际类型
fun content(content: String): Self
this.content = content
return self
open fun build() = Notification(this.title, this.content)
class ConfirmNotificationBuilder : NotificationBuilder<ConfirmNotificationBuilder>()
private var onConfirm: OnConfirm = EmptyFunction
private var onCancel: OnCancel = EmptyFunction
fun onConfirm(onConfirm: OnConfirm): ConfirmNotificationBuilder
this.onConfirm = onConfirm
return this
fun onCancel(onCancel: OnCancel): ConfirmNotificationBuilder
this.onCancel = onCancel
return this
override fun build() = ConfirmNotification(title, content, onConfirm, onCancel)
fun main()
ConfirmNotificationBuilder()
.title("Hello")
.onCancel
println("onCancel")
.content("World")
.onConfirm
println("onConfirmed")
.build()
.onConfirm()
如果不定义SelfType类型,则子类在调用ConfirmNotificationBuilder().title(“Hello”)之后不能再继续调用子类的onCancel 方法,因为返回的是父类型,但是实际运行时这个类型是子类型。
实例: 基于泛型实现 Model 实例的注入
import java.util.concurrent.ConcurrentHashMap
import kotlin.reflect.KProperty
abstract class AbsModel
init
Models.run this@AbsModel.register()
class DatabaseModel : AbsModel()
fun query(sql: String): Int = 0
class NetworkModel : AbsModel()
fun get(url: String): String = """"code": 0"""
class SpModel : AbsModel()
init
Models.run register("SpModel2")
fun hello() = println("HelloWorld")
object Models
private val modelMap = ConcurrentHashMap<String, AbsModel>()
fun AbsModel.register(name: String = this.javaClass.simpleName)
modelMap[name] = this
//String扩展函数
fun <T: AbsModel> String.get(): T
return modelMap[this] as T
fun initModels()
DatabaseModel()
NetworkModel()
SpModel()
//object单例
object ModelDelegate
operator fun <T: AbsModel> getValue(thisRef: Any, property: KProperty<*>): T
return Models.run
property.name.capitalize().get() //利用了String的扩展函数
class MainViewModel
//利用属性代理by by左边指定类型推导泛型
val databaseModel: DatabaseModel by ModelDelegate
val networkModel: NetworkModel by ModelDelegate
val spModel: SpModel by ModelDelegate
val spModel2: SpModel by ModelDelegate
// val compileKotlin: KotlinCompile by tasks //gradle这种写法类似,tasks也是属性代理
// val compileTestKotlin: KotlinCompile by tasks
fun main()
initModels()
val mainViewModel = MainViewModel()
mainViewModel.databaseModel.query("select * from mysql.user").let(::println)
mainViewModel.networkModel.get("https://www.imooc.com").let(::println)
mainViewModel.spModel.hello()
mainViewModel.spModel2.hello()
以上是关于Kotlin学习手记--泛型泛型约束泛型型变星投影泛型擦除内联特化的主要内容,如果未能解决你的问题,请参考以下文章