多应用+插件架构,代码干净,二开方便,首家独创一键云编译技术,文档视频完善,免费商用码云13.8K 广告
# 1. 泛型 **泛型**是一种编译时的安全检测机制,它允许在定义类、接口、方法时使用类型参数,声明的类型参数在使用时用具体的类型来替换。泛型的**本质是参数化类型**,也就是说所操作的数据类型被指定为一个参数。其实在之前的小节中也用到过泛型,且其用法和`Java`中基本一致,所以这里就简略介绍。 # 2. 泛型类 **泛型符号**可以是满足`Kotlin`命名规则的任意字符,甚至可以是某一个单词。比如下面的案例: ~~~ data class KotlinDemo<N, A>(var name: N, var age: A) { override fun toString(): String { return "KotlinDemo(name=$name, age=$age)" } } fun main() { var demo = KotlinDemo<String, Int>("张三", 24) println(demo) } ~~~ 结果: ``` KotlinDemo(name=张三, age=24) ``` 至于用在方法和接口上的使用类似,这里就不再继续给出案例。 # 3. 泛型约束 注意到上面的方式仅仅只是简单的应用,而实际上还有泛型约束。比如在`Java`中提供了`super`和`extends`关键字来进行。在`Kotlin`中类似的可以进行对类型的约束。 - `<? extends类或接口> ` 类比于: `<T:类或接口>`。可以理解为泛型的上界,因为在`Kotlin`中使用`:`来表示继承关系。 比如下面的案例: ~~~ open class Animal{ var weight = 30 } // 继承 class Cat: Animal() { var name = "Cat" override fun toString(): String { return "Cat(name='$name', weight=$weight)" } } class KotlinDemo<T: Animal> (animal: T){ private var demo: T? = null init { if(this.demo == null) { this.demo = animal } } override fun toString(): String { return "KotlinDemo(demo=$demo)" } } fun main() { var demo = KotlinDemo<Cat>(Cat()) println(demo) } ~~~ 结果: ``` KotlinDemo(demo=Cat(name='Cat', weight=30)) ``` # 4. 协变与逆变 协变与逆变其实是`C#`语言`4.0`以后新增的高级特性,**协变**是将父类变为具体子类,协变类型作为消费者,只能读取不能写入,**逆变**是将子类变为具体父类,逆变作为生产者,只能写入不能读取。 - **协变**,父类变子类,只能读取(`out`); - **逆变**,子类变父类,只能写入(`in`); 对于`in`和`out`这两个单词的简单理解记忆图示: ![](https://img.kancloud.cn/de/d4/ded4f553c090c91072729af78abe8f1b_349x301.png) 上图来自视频:[Kotlin教程](https://www.bilibili.com/video/BV1wf4y1s7TG?p=114) 这么说起来比较抽象,这里直接给出两个案例。 ## 4.1 案例一:逆变 ~~~ // 逆变,只写,作为函数参数 interface Consumer<in T>{ fun consume(item: T) } open class Animal class Cat: Animal() class KotlinDemo2: Consumer<Animal> { override fun consume(item: Animal){ } } fun main() { var consumer1: Consumer<Cat> = KotlinDemo2() } ~~~ ## 4.2 案例二:协变 ~~~ // 协变,只读,即仅作为返回值 interface Producer<out T>{ fun produce(): T } open class Animal class Cat: Animal() class KotlinDemo2: Producer<Animal> { override fun produce(): Animal{ return Animal() } } class KotlinDemo1: Producer<Cat> { override fun produce(): Cat { return Cat() } } fun main() { var consumer1: Producer<Animal> = KotlinDemo1() } ~~~ 父变子指的是:要求是`Animal`,但是赋值的为子类对象。 # 5. 泛型类型检查 有时候我们需要对传入的泛型的类型做一个检查,而在`Java`中我们通常使用反射来获取类型进而进行判断,比如: ~~~ interface B<T>{ T getInstance(T t); } public class A<T> implements B<T>{ @Override public T getInstance(T t) { if(t.getClass().getName() .equals("com.kotlinLearn.Animal")){ return t; } return (T) new Cat(); } public static void main(String[] args) { A<Animal> a = new A<>(); Animal instance = a.getInstance(new Cat()); System.out.println(instance.getClass().getName()); } } ~~~ 结果: ``` com.kotlinLearn.Cat ``` 而在`Kotlin`中就不需要这么麻烦,可以直接使用关键字`inline`和`reified`进行判断: ~~~ open class Animal class Cat: Animal() class B{ inline fun<reified T> getInstance(item: () -> T): T { val animal = Animal() return if(animal is T){ animal } else{ item() } } } ~~~