
本章总结 : 使用了 泛型 out 协变 和 泛型 in 逆变 极大的提高了程序的扩展性 ;
使用 out 关键字 , 可以使 子类泛型对象 赋值给 父类泛型对象 ;

在 泛型类 中 , 如果只将 泛型类型 作为 函数的返回值 类型 , 则在 声明 泛型参数 类型 时 , 在 泛型参数 前 使用 out 关键字 , 同时 该 泛型类 又称为 生产类 ( 生产接口 ) , 用于生产 泛型类 指定的泛型对象 ;
代码示例 : 在下面的接口中 , 泛型类型 只用于作为 返回值 ;
interface Producer<out T> {
fun produce(): T
}使用 in 关键字 , 可以使 父类泛型对象 赋值给 子类泛型对象 ;

在 泛型类 中 , 如果只将 泛型类型 作为 函数的参数 类型 , 则在 声明 泛型参数 类型 时 , 在 泛型参数 前 使用 in 关键字 , 同时 该 泛型类 又称为 消费类 ( 消费接口 ) , 用于消费 泛型类 指定的泛型对象 ;
代码示例 : 在下面的接口中 , 泛型类型 只用于作为参数 ;
interface Consumer<in T> {
fun consume(t: T)
}在 泛型类 中 , 如果
则在 声明 泛型参数 类型 时 , 既不使用 in 关键字 , 又不使用 out 关键字 ;
代码示例 : 在下面的接口中 , 泛型类型 即用于作为 返回值 , 又用于作为参数 ;
interface ProducerOrConsumer<T> {
fun produce(): T
fun consume(t: T)
}泛型类 中 泛型参数 有 子类 和 父类 ,
import java.util.ArrayList;
public class HelloAWT {
public static void main(String[] args) {
ArrayList<CharSequence> list = new ArrayList<String>();
}
}
下图中 父类范围 比 子类范围 大 ,

使用了 泛型 out 协变 和 泛型 in 逆变 极大的提高了程序的扩展性 ;
在下面的代码中 , FoodFactory 是 Producer<Food> 子类 , 类型正好匹配 ;
// FoodFactory 是 Producer<Food> 子类 , 类型正好匹配
val producer: Producer<Food> = FoodFactory();FastFoodFactory 是 Producer<FastFood> 子类 , Producer 的泛型参数 FastFood 是 Food 的子类 , 在 Kotlin 中 , 可以将 Producer<FastFood> 类型赋值给 Producer<Food> 类型 , 在 Java 中这种用法不行 ;
// FastFoodFactory 是 Producer<FastFood> 子类
// Producer 的泛型参数 FastFood 是 Food 的子类
// 在 Kotlin 中 , 可以将 Producer<FastFood> 类型赋值给 Producer<Food> 类型
// 在 Java 中这种用法不行
val producer2: Producer<Food> = FastFoodFactory();代码示例 :
import java.util.*
interface Producer<out T> {
fun produce(): T
}
interface Consumer<in T> {
fun consume(t: T)
}
interface ProducerOrConsumer<T> {
fun produce(): T
fun consume(t: T)
}
open class Food
open class FastFood : Food()
class Burger : FastFood()
class FoodFactory : Producer<Food> {
override fun produce(): Food {
println("生产食物")
return Food()
}
}
class FastFoodFactory : Producer<FastFood> {
override fun produce(): FastFood {
println("生产快餐")
return FastFood()
}
}
class BurgerFactory : Producer<Burger> {
override fun produce(): Burger {
println("生产汉堡")
return Burger()
}
}
class People : Consumer<Food> {
override fun consume(t: Food) {
println("人吃食物")
}
}
class ModernPeople : Consumer<FastFood> {
override fun consume(t: FastFood) {
println("现代人吃快餐")
}
}
class WestModernPeople : Consumer<Burger> {
override fun consume(t: Burger) {
println("西方现代人喜欢吃汉堡")
}
}
fun main() {
// I. 泛型 out 协变 , 使用 out 关键字 , 可以使 子类泛型对象 赋值给 父类泛型对象
// FoodFactory 是 Producer<Food> 子类 , 类型正好匹配
val producer: Producer<Food> = FoodFactory();
producer.produce()
// FastFoodFactory 是 Producer<FastFood> 子类
// Producer 的泛型参数 FastFood 是 Food 的子类
// 在 Kotlin 中 , 可以将 Producer<FastFood> 类型赋值给 Producer<Food> 类型
// 在 Java 中这种用法不行
val producer2: Producer<Food> = FastFoodFactory();
producer2.produce()
// II. 泛型 in 逆变 , 使用 in 关键字 , 可以使 父类泛型对象 赋值给 子类泛型对象
// People 的类型是 Consumer<Food>
// consumer 的类型是 Consumer<Burger>
// 在 Consumer 中 , 使用了泛型参数 in 逆变
// 泛型参数是父类 的泛型类对象 可以赋值给 泛型参数是子类 的泛型对象
val consumer : Consumer<Burger> = People()
consumer.consume(Burger())
}执行结果 :
生产食物
生产快餐
人吃食物泛型参数类型 T 在 运行时 会被 类型擦除 , 因此 在运行时 是 不知道 泛型参数 的 具体类型 的 ,
借助 reified 关键字 可以检查 运行时 泛型参数 的 具体类型 ;
在 Java 中 , 运行时 不知道 泛型参数 的 具体类型 ; 在 Kotlin 中可以 通过 reified 关键字检查 泛型参数类型 ;
Java 中如果想要知道 泛型参数 具体类型 , 通过常规的方法无法实现 , 通过 反射 可以实现 ;
Java 泛型类对象.javaClass.name == "要判断的类的全类名"在 函数 中 使用 reified 关键字 , 需要在 尖括号 <> 中 泛型类型 之前 添加 reified 关键字 , 此外 函数 还要 使用 inline 关键字 进行修饰 ;
inline fun <reified T> 函数名(t: T): T {}使用了 reified 关键字 修饰 泛型 的 inline 函数 中 , 可以 使用 is 判定 泛型参数的具体类型 ;
代码示例 :
open class Food
open class FastFood : Food()
class Burger : FastFood()
class Student<T: Food> () {
inline fun eat(food: T) {
if (food is Burger) {
println("吃汉堡")
} else if (food is FastFood) {
println("吃快餐")
} else if (food is Food) {
println("吃普通食物")
}
}
}
fun main() {
val student = Student<Food>()
student.eat(Food())
val student2 = Student<FastFood>()
student2.eat(FastFood())
val student3 = Student<Burger>()
student3.eat(Burger())
}执行结果 :
吃普通食物
吃快餐
吃汉堡