泛型中的extends和super的区别

在网上看到如下代码,不知道为什么报错,代码如下:

public class GenericTest {  
  
    public static void main(String[] args) throws Exception {  
  
       List<? super Fruit> f0=new ArrayList<Fruit>();  
       f0.add(new Apple());  
       f0.add(new Fruit());  
       f0.add(new SupApple());  
         
       List<? super Fruit> f1=new ArrayList<Apple>();  
       f1.add(new Apple());  
       f1.add(new Fruit());  
         
       List<? extends Fruit> f2=new ArrayList<Fruit>();  
       f2.add(new Apple());  
       f2.add(new Fruit());   
         
       List<? extends Fruit> f3=new ArrayList<Apple>();  
       f3.add(new Apple());  
       f3.add(new Fruit());  
          
       List<? super Apple> f5=new ArrayList<Fruit>();  
       f5.add(new Apple());  
       f5.add(new SupApple());  
       f5.add(new Fruit());  
    }  
}  
 
class Fruit{  
}  
class Apple extends Fruit{  
}   
class SupApple extends Apple{      
} 


首先说下extends和super的却别(参考:点击打开链接):

extends

List<? extends Number> foo3的通配符声明,意味着以下的赋值是合法的:

List<? extends Number> foo3 = new ArrayList<? extends Number>();

List<? extends Number> foo3 = new ArrayList<? extends Integer>();

List<? extends Number> foo3 = new ArrayList<? extends Double>();

  1. 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你可以读取到Number,因为以上的列表要么包含Number元素,要么包含Number的类元素。

    你不能保证读取到Integer,因为foo3可能指向的是List<Double>。

    你不能保证读取到Double,因为foo3可能指向的是List<Integer>。

  2. 写入操作过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?

    你不能插入一个Integer元素,因为foo3可能指向List<Double>。

    你不能插入一个Double元素,因为foo3可能指向List<Integer>。

    你不能插入一个Number元素,因为foo3可能指向List<Integer>。

    你不能往List<? extends T>中插入任何类型的对象,因为你不能保证列表实际指向的类型是什么,你并不能保证列表中实际存储什么类型的对象。唯一可以保证的是,你可以从中读取到T或者T的子类。

super

现在考虑一下List<? super T>。

List<? super Integer> foo3的通配符声明,意味着以下赋值是合法的:

List<? super Integer> foo3 = new ArrayList<Integer>();

List<? super Integer> foo3 = new ArrayList<Number>();

List<? super Integer> foo3 = new ArrayList<Object>();

  1. 读取操作通过以上给定的赋值语句,你一定能从foo3列表中读取到的元素的类型是什么呢?你不能保证读取到Integer,因为foo3可能指向List<Number>或者List<Object>。

    你不能保证读取到Number,因为foo3可能指向List<Object>。

    唯一可以保证的是,你可以读取到Object或者Object子类的对象(你并不知道具体的子类是什么)。

  2. 写入操作通过以上给定的赋值语句,你能把一个什么类型的元素合法地插入到foo3中呢?你可以插入Integer对象,因为上述声明的列表都支持Integer。

    你可以插入Integer的子类的对象,因为Integer的子类同时也是Integer,原因同上。

    你不能插入Double对象,因为foo3可能指向ArrayList<Integer>。

    你不能插入Number对象,因为foo3可能指向ArrayList<Integer>。

    你不能插入Object对象,因为foo3可能指向ArrayList<Integer>。

通过网上查找,最终明白了:

public static void main(String[] args) throws Exception {  
    	//定义正确,使用正确。
		List<? super Fruit> f0 = new ArrayList<Fruit>();
		f0.add(new Apple());
		f0.add(new Fruit());
		f0.add(new SupApple());

		List<? super Fruit> f1 = new ArrayList<Apple>(); // ArrayList泛型中的只能是Fruit或者Object,即Fruit本身或者Fruit的父类类型。
		f1.add(new Apple());
		f1.add(new Fruit());

		//定义正确,使用错误。
		List<? extends Fruit> f2 = new ArrayList<Fruit>();
		//添加了Apple,f2有可能指向ArrayList<SupApple>
		f2.add(new Apple());
		//添加了Fruit,f2有可能指向ArrayList<SupApple>/ArrayList<Apple>
		f2.add(new Fruit());

		//定义正确,使用错误。
		List<? extends Fruit> f3 = new ArrayList<Apple>();
		//添加了Apple,f3有可能指向ArrayList<SupApple>
		f3.add(new Apple());
		//添加了Apple,f3有可能指向ArrayList<SupApple>/ArrayList<Apple>
		f3.add(new Fruit());

		//只能添加Apple以及Apple的子类
		List<? super Apple> f5 = new ArrayList<Fruit>();
		f5.add(new Apple());
		f5.add(new SupApple());
		f5.add(new Fruit());
		
		/**
		 * 总结:
		 * 		extends,只能读取,不能写。
		 * 		super:可以读取,且只能返回Object类型,或Object的子类对象(但是不能确定具体的子类是什么)
		 * 			      可以写,? super Xxx ,只能写Xxx或Xxx的子类对象。
		 */
		
    }  



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值