什么是refied关键字
由于我们都知道Kotlin和Java一样都存在着泛型擦除问题,而Kotlin它知道Java所带来的这个问题,所以对此Kotlin留了一个后门,就是通过inline函数保证使得泛型类的类型实参在运行时能够保留,这样的操作 Kotlin 中把它称为实化,对应需要使用 reified 关键字。而 reified意为具体化,使得(抽象的东西)变得更加具体化,它是Kotlin所增强的一种泛型的使用方式;
当然,使用reified关键字必要条件如下:
必须是 inline 内联函数,使用 inline 关键字修饰;
泛型类定义泛型形参时必须使用 reified 关键字修饰;
reified背后的故事
既然我们知道reified和inline函数是相辅相成的,使用inline函数的最大一个好处就是函数调用的性能优化和提升,需要注意的是reflied使用 inline 函数并不是因为性能的问题,而是另外一个好处它能使泛型函数类型实参进行实化,在运行时能拿到类型实参的信息,相当于带实化参数的函数每次调用都生成不同类型实参的字节码,动态插入到调用点。由于生成的字节码的类型实参引用了具体的类型,而不是类型参数所以不会存在擦除问题;
综上所述,这也是为啥reifiied关键字必须使用inline关键字修饰的原因。换句话说,使用reifled可以保证泛型类的类型实参可以在运行中被保留,由于是具体的参数类型,可有效避免了泛型擦除的问题。
sam转换
在Kotlin中,SAM的概念其实是从Java那边追溯过来的,在Java中,我们把单一方法的接口叫做SAM(Single Abstract Method)接口,从Java8之后通过Lambda可以大大简化对于SAM接口的调用。所以SAM就代表的是单一抽象方法,“SAM类型”是指像Runnable,Callable等接口;Lambda表达式其实就可以被认为是SAM类型,可以自由转换为它们。
示例:(谱写Kotlin面试指南三部曲-基础篇 - 掘金,个人实测不行)
fun main() {
//方案一:匿名类对象
buyCar(object : IBuy {
override fun onBuy(money: Double) {
println("buyCar:$money")
}
})
//方案二:SAM构造方法
buyCar(IBuy {
println("BuyCar:$it")
})
//方案三:SAM构造方法(推荐)
buyCar({
println("BuyCar:$it")
})
//方案四:SAM构造方法(推荐)
buyCar {
println("BuyCar: $it")
}
}
//买一辆一千万的车
fun buyCar(buy: IBuy) {
buy.onBuy(10000000.0)
}
fun interface IBuy {
fun onBuy(money: Double)
}
因此,我们借助Lambda表达式对SamType调用的优化称为SAM转换(Single Abstract Method Conversions),Kotlin对此已经兼容了Java中的SAM转换,它只是将Java的SamType翻译成了Lambda,因此在kotlin的同名方法实际变成了一个高阶函数。
个人实测报错