1、泛型概念
//方法声明泛型
fun <T> test1(a: T, b: T) {
}
fun <T, R> test2(a: T, b: R) {
}
//类声明泛型
class Test<T> {
fun test(t: T) {
}
}
2、泛型约束
//泛型约束
//约束T必须是Comparable的子类,必须实现了Comparable接口
//实现了Comparable接口才能比较大小
fun <T : Comparable<T>> maxOf(a: T, b: T) = if (a > b) a else b
//多个约束
//利用where设置多个约束
fun <T, R> callMax(a: T, b: T): R
where T : Comparable<T>,
T : () -> R,
R : Number {
return if (a > b) a() else b()
}
//T : () -> R 表示T是一个没有参数的方法,返回值是Number类型
val result: Double = callMax({
3.14 }, {
2.71 })
3、协变逆变
3.1 协变
//协变 out
//协变点:泛型参数作为方法返回值
//存在协变点的类的泛型参数必须声明为协变或不变
interface Book
interface EducationBook : Book
class BookStore<out T : Book> {
fun getBook(): T {
TODO()
}
}
fun buyBook() {
//父类:Book 子类:EducationBook
//父类:bookStore 子类:educationBookStore
//子类可以赋值给父类
val educationBookStore: BookStore<EducationBook> = BookStore()
val bookStore: BookStore<Book> = educationBookStore
val book: Book = bookStore.getBook()
val educationBook: EducationBook = educationBookStore.getBook()
//子类中可以获取到父类的值
val book2: Book = educationBookStore.getBook()
}
3.2 逆变
//逆变 in
//逆变点:泛型参数作为方法的形参
//存在逆变点的类的泛型参数必须声明为逆变或不变
open class Fruit
class Apple : Fruit()
class Person<in T : Fruit> {
fun eat(t: T) {
}
}
fun eatFruit() {
//父类:Fruit 子类:Apple
//父类:personEatApple 子类:personEatFruit
val personEatFruit: Person<Fruit> = Person()
val personEatApple: Person<Apple> = personEatFruit
personEatApple.eat(Fruit()) //错误
personEatApple.eat(Apple())
//子类personEatFruit可以替换所有类型
personEatFruit.eat(Fruit())
personEatFruit.eat(Apple())
}
3.3 举例
//协变举例
//stuId的T是协变点, 因为T是属性getter()的返回值
data class Student<out T>(
val stuId: T
)
class Teacher<out N, out A> {
private var name: N? = null
private var age: A? = null
}
3.4 UnsafeVariance
协变点逆变
class Test<out T> {
//协变
private var param: T? = null
fun getParam(): T? = param
//协变点逆变, 只写不读
fun setParam(t: @UnsafeVariance T) {
param = t
}
}
逆变点协变
class Test<in T> {
//逆变
private var param: T? = null
fun setParam(t: T) {
param = t
}
//逆变点协变, 只读不写
fun getParam(): @UnsafeVariance T? {
return param
}
}
4、星投影
- ‘*’ 可用在变量类型声明的位置
- ‘*’ 可用以描述一个未知的类型
‘*’ 所替换的类型在:
- 协变点 返回 泛型参数上限类型 (协变上限)
- 逆变点 接收 泛型参数下限类型 (逆变下限)
协变点
//父类
open class Fruit
//子类
class Apple() : Fruit()
//父类
open class Animal
//子类
class Cat() : Animal()
//定义
class MyHouse<out T1 : Fruit, out T2 : Animal> {
private var thing1: T1? = null
private var thing2: T2? = null
fun getThing1(): T1? = thing1
fun getThing2(): T2? = thing2
}
//使用
fun main() {
val myHouse: MyHouse<*, *> = MyHouse<Apple, Cat>()
val t1 = myHouse.getThing1() //t1是Fruit类型, 因为Apple的上限是Fruit
val t2 = myHouse.getThing2() //t2是Animal类型, 因为Cat的上限是Animal
}
逆变点
//逆变下限是Nothing,Nothing是无法实例化的
class Test<in T1, in T2> {
private var param1: T1? = null
private var param2: T2? = null
fun set(t1: T1, t2: T2) {
param1 = t1
param2 = t2
}
}
fun main() {
val test: Test<*, *> = Test<String, String>()
test.set("param1", "param2") //错误, Nothing类型不可以实例化,不可以用"param1", "param2"对其赋值
}
星投影适用范围
//不可以直接或间接应用在属性或函数上
val map = HashMap<String, *>() //错误
val max = maxOf<*>(1, 2, 3) //错误
//适用于作为类型描述场景
val map2: HashMap<*, *> = HashMap<String, Int>()
map2.put("leon", 26) //错误, 逆变下限Nothing类型无法赋值String,Int
val f: Function2<Int, Int, String> = {
a, b ->
"The sum of $a and $b is ${
a + b}"
}
if (f is Function2<*, *, *>) {
f.invoke(1, 2)
}
if (f is Function) {
f.invoke(1, 2)
}
val map3 = HashMap<String, List<*>>() //因为kotlin不支持高阶类型, 所以不管*传的是什么, 对HashMap而言都是List