List和List>的区别
类型参数“
无界通配符“>主要用于泛型类或泛型方法。
声明泛型类的类型参数
public class ArrayList extends AbstractList
implements List, RandomAccess, Cloneable, java.io.Serializable
{}
声明泛型方法
public class aaa {
public void fun(T b) {
}
}
public class aaa {
public void fun(T b) {
}
}
//类后面的泛型T 和 方法前面的泛型T 不是同一个泛型, 可以理解T 和E
public class aaa {
public void fun(E b) {
}
}
- >的使用
List> list = new ArrayList();
通配符会捕获具体的类型String,但是编译器不叫他String 而是起一个临时代号,所以不能往里面存任何非null元素
? super T和? extends T区别
- extends T>:上界通配符(Upper Bounds Wildcards)
包括T在内的任何T的子类
List extends Number> foo3 = new ArrayList extends Number>();
List extends Number> foo3 = new ArrayList extends Integer>();
List extends Integer> foo3 = new ArrayList extends Number>(); //编译不通过
- 读取操作通过以上给定的赋值语句,可以读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素
- 添加操作, 不能往List extends T>中插入任何类型的对象,因为不能保证列表实际指向的类型是什么,你并不能保证列表中实际存储什么类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。
- super T>:下界通配符(Lower Bounds Wildcards)
包括T在内的任何T的父类
List super Integer> foo3 = new ArrayList();
List super Integer> foo3 = new ArrayList();
List super Number> foo3 = new ArrayList(); //编译报错
读取操作通过以上给定的赋值语句,你不能保证读取到Integer,因为foo3可能指向List
或者List 写入操作通过以上给定的赋值语句,你可以插入Integer对象,因为上述声明的列表都支持Integer。你可以插入Integer的子类的对象,因为Integer的子类同时也是Integer,原因同上。
使用场景
- PECS :生产者(Producer)使用extends,消费者(Consumer)使用super。
生产者使用extends
如果你需要一个列表提供T类型的元素(即你想从列表中读取T类型的元素),你需要把这个列表声明成 extends T>,比如List extends Integer>,因此你不能往该列表中添加任何元素。消费者使用super
如果需要一个列表使用T类型的元素(即你想把T类型的元素加入到列表中),你需要把这个列表声明成 super T>,比如List super Integer>,因此你不能保证从中读取到的元素的类型。
public static void copy(List super T> dest, List extends T> src) {
int srcSize = src.size();
if (srcSize > dest.size())
throw new IndexOutOfBoundsException("Source does not fit in dest");
if (srcSize < COPY_THRESHOLD ||
(src instanceof RandomAccess && dest instanceof RandomAccess)) {
for (int i=0; i di=dest.listIterator();
ListIterator extends T> si=src.listIterator();
for (int i=0; i
java.util.Collections里的copy方法使用到了PECS原则,实现了对参数的保护。
- 类型兼容
class A {
}
class B extends A {
}
private void testFun () {
ArrayList a = new ArrayList(); //编译报错
}
编译报错, 编译器在确定 ArrayList 元素类型的时候不会考虑 A 和 B 的继承关系,编译器无法承认第二行代码是合法的。为了解决这个问题引入了通配符的概念。
ArrayList a = new ArrayList(); 改为 ArrayList extends A> a = new ArrayList(); 编译成功
- 类型限制
Rxjava Observable.map方法数据转换时,将源数据和返回数据使用了通配符限制
public final Observable map(Func1 super T, ? extends R> func) {
return lift(new OperatorMap(func));
}
自定义泛型类时候,限制参数类型
public static class aaa {
public void call(func super Number> f) {
f.call(1);
}
}
public static class bbb {
private T t;
public void call(func super T> f) {
f.call(t);
}
}
public interface func {
void call(T t);
}
public static void main() {
new aaa().call(new func() {
@Override
public void call(Number number) {
}
});
new bbb().call(new func() {
@Override
public void call(Number o) {
}
});
}
误区
public static class bbb {
private T t;
public void call(func super T> f) {
f.call(t);
}
}
public interface func {
void call(T t);
}
public static void main() {
// 这里传入子类 为什么没有报错
new bbb().call(new func() {
@Override
public void call(Number o) {
}
});
}
因为 new
public static class bbb {
private T t;
bbb(E e){
}
}
public static void main() {
new bbb(1).call(new func() {
@Override
public void call(String o) {
}
});
}
正确写法应该是这样
https://ask.csdn.net/questions/7711251?weChatOA=