看了几篇博客,发现写的不是很通俗易懂,所以自己撸一篇
如下是代码:
首先我们创建了两个类Fruit ,Orange 分别是父子的关系;
public class Generics {
static class Fruit {
}
static class Orange extends Fruit {
}
public static void main(String... args) throws Exception {
List<? extends Fruit> list = new ArrayList<>();
//第一处错误:无法安全添加不确定类型的元素
list.add(new Orange());
list.add(null);
Fruit fruit = list.get(0);
Orange orange = (Orange) list.get(0);
//父类可以接收子类对象
Fruit fruit1 = new Orange();
//第三处错误:子类不可以接收父类对象
Orange orange1 = new Fruit();
//父类可以强转子类对象
Orange orange2 = (Orange) new Fruit();
Orange orange3 = (Orange) list.get(0);
List<? super Fruit> list1 = new ArrayList<>();
list1.add(new Orange());
//第二处错误:无法确定具体的返回类型
Fruit fruit2 = list1.get(0);
Orange orange4 = (Orange) list1.get(0);
}
}
可以看到如上代码有三处编译错误
第一处错误:
首先是这个List<? extends Fruit>不能添加Orange对象;
虽然List<? extends Fruit> 表示是该List存放的是Fruit类对象或者Fruit子类对象;
但是编译器无法确定List所持有的类型,所以无法安全的向其中添加对象(比如String和Integer都是Object的子类,但是在确定泛型为String的List< String>中是不能放Integer的);
由于list里面的顶级类型是Fruit,所以可以安全取出Fruit类型 ;
//无法安全添加不确定类型的元素
list.add(new Orange());
第二处错误:
List<? super Fruit>无法取出Fruit类型对象;
由于List<? super Fruit>存放的至少是一个Fruit类型,因此可以安全的向其中添加Fruit及其子类型(比如List< Object >里面可以存放String也可以放Integer);
由于list里面的类型是从Fruit的父类,编译器无法确定返回的类型,所以直接取值时会报错(其实是无法确定接收类型,这里就要提到第三处报错,大家接着往下看);
//无法确定具体的返回类型
Fruit fruit2 = list1.get(0);
第三处错误:
这条就是用来解释为什么list1.get(0)不能用Fruit 类型接收,子类类型不可以直接接收父类对象(其实通过强转或者用Object也能接收)
//子类不可以接收父类对象
Orange orange1 = new Fruit();
小结:
List<? extends Fruit> 可用于的返回类型限定,不能用于参数类型限定。
List<? super Fruit> 可用于参数类型限定,不能用于返回类型限定。
希望只取出,不插入,就使用? extends
希望只插入,不取出,就使用? super
希望,即能插入,又能取出,就不要用通配符
以上为个人理解,有不足的地方,还请各位指出