java
中泛型通常用法
List<TextView> textViews = new ArrayList<TextViews>();
List
集合中生命泛型的类型
注意,java
泛型不适合多态,比如:
//java的多态
TextView textview = new Button(context);
List<Button> buttons = new ArrayList<Button>();
List<TextView> textViews = buttons;
//IDE会报错
Button
是TextView
的子类,但是List
不属于List
的子类,java
的泛型在编译的时候会类型擦除
,而数组没有问题。比如
//todo
TextView
java
提供了泛型通配符? extend
,上界通配符,是java泛型
具有协变性 Covariance
List<Button> buttons = new ArrayList<Button>();
//使用泛型通配符
List<? extends TextView> textViews = buttons;
extends
限制了泛型的上限,正常使用情况
List<? extends TextViews> textViews = new ArrayList<TextVies>();//本身
List<? extends TextViews> textViews = new ArrayList<Button>();//直接子类
List<? extends TextViews> textViews = new ArrayList<RadioButton>();//间接子类
有泛型的List
集合,可以正常get
元素数据,但是add
操作的时候会报错。因此只能向外提供数据,即是生产者Producer
.
java
中的? super
,下界通配符,使java泛型
具有逆变性 Contravariance
List<? super Button> buttons = new ArrayList<TextViews>();
正常的使用情况
List<? super Button> buttons = new ArrayList<Button>(); //本身
List<? super Button> buttons = new ArrayList<TextView>(); //直接父类
List<? super Button> buttons = new ArrayList<Object>(); //间接父类
使用下界通配符? super
的泛型的get
操作,得到的元素只能是Object
,而add
操作是可以的。这种泛型类型称为消费者Consumer
java
泛型总结
1.可以使用泛型通配符 ? extends 来使泛型支持协变,但是「只能读取不能修改」,这里的修改仅指对泛型集合添加元素,如果是 remove(int index) 以及 clear 当然是可以的。
2.可以使用泛型通配符 ? super 来使泛型支持逆变,但是「只能修改不能读取」,这里说的不能读取是指不能按照泛型类型读取,你如果按照 Object 读出来再强转当然也是可以的。
被称为PECS法则,「Producer-Extends, Consumer-Super」
kotlin
中主要使用in
和out
关键字
out
支持协变
,等同于java
的上界通配符? extend
in
支持逆变
,等同于java
的下界通配符? super
out
表示只输出
,即只读
,in
表示只输入
,即只写
val textViews: List<out TextView>
val textViews: List<in TextView>
非集合类的使用,生产者
class Producer<T> {
fun produce(): T {
...
}
}
val producer: Producer<out TextView> = Producer<Button>()
val textView: TextView = producer.produce()//相当于list的get
消费者
class Consumer<T>{
fun consume(t: T) {
...
}
}
val consumer: Comsumer<in Button> = Consumer<TextView>()
consumer.consumer(Button(context)) // 相当于list的add
生产者的代码中可以把out
放在类声明处,之后声明变量可以不用加out
class Producer<out T> {
fun produce(): T {
...
}
}
//省略掉out
val producer: Producer<TextView> = Producer<Button>()
val textView: TextView = producer.produce()//相当于list的get
相同的,消费者的代码中,可以把in
放在类声明处
class Consumer<in T>{
fun consume(t: T) {
...
}
}
//省略in
val consumer: Comsumer<Button> = Consumer<TextView>()
consumer.consumer(Button(context)) // 相当于list的add
*
号
where
关键字
java
在使用
的时候(注意是T extends 不是 ? extends)
class Monster<T extends Animal>{}
还可以设置多个
class Monster<T extends Animal & Food>{}
kotlin
中只是把extends
换成了:
class Monster<T : Animal>{}
设置多个的时候
class Monster<T> where T: Animal,T: Food{}
如果Monster
本身还有继承的时候
class Monster<T> : MonsterParent<T>
where T:Animal
reified
关键字
java
中的泛型存在类型擦除
<T> void printIfTypeMatch(Object item) {
if (item instanceof T) { // 报错
System.out.println(item);
}
}
解决方案就是再传递一个参数Class
类型
<T> void check(Object item, Class<T> type) {
if (type.isInstance(item)) {
System.out.println(item);
}
}
Kotlin
中可以使用reified
关键字
inline fun <reified T> printIfTypeMatch(item: Any) {
if (item is T) {
println(item)
}
}