zoukankan      html  css  js  c++  java
  • 一文搞懂List 、List<Object>、List<?>的区别以及<? extends T>与<? super T>的区别

    前段时间看《Java编程思想》泛型时对 <? extends T>与<? super T>很懵逼,接着看到泛型与集合的更蒙蔽,随后又翻开《码出高效》时,对这些知识点才恍然大悟,发篇博客记录下

    List、List<Object>、List<?> 的三者的区别以及 <? extends T>与<? super T> 的区别

    List、List<Object>、List<?>

    • List :完全没有类型限制和赋值限定。
    • List<Object> :看似用法与List一样,但是在接受其他泛型赋值时会出现编译错误。
    • List<?>:是一个泛型,在没有赋值前,表示可以接受任何类型的集合赋值,但赋值之后不能往里面随便添加元素,但可以remove和clear,并非immutable(不可变)集合。List<?>一般作为参数来接收外部集合,或者返回一个具体元素类型的集合,也称为通配符集合

    代码验证:(感觉用博客的页面插入代码效果不好,在此处贴了图片,代码在文章末尾补上)
    在这里插入图片描述
    <? extends T>与<? super T>

    List 最大的问题是只能放置一种类型,如果随意转变类型的话,就是破窗理论,泛型就失去了意义。为了放置多种受泛型约束的类型,出现了 <? extends T>与<? super T> 两种语法。简单来说, <? extends T> 是Get First,适用于,消费集合元素的场景;<? super T>是Put First,适用于,生产集合元素为主的场景。

    • <? extends T> :可以赋值给任意T及T的子类集合,上界为T,取出来的类型带有泛型限制,向上强制转型为T。null 可以表示任何类型,所以null除外,任何元素都不得添加进<? extends T>集合内。
    • <? super T> : 可以复制T及任何T的父类集合,下界为T。再生活中,投票选举类似于<? super T>的操作。选举投票时,你只能往里投票,取数据时,根本不知道时是谁的票,相当于泛型丢失

    <? extends T>的场景是put功能受限,而<? super T>的场景是get功能受限

    代码示例如下(以加菲猫、猫、动物为例,说明extends和super的详细语法差异0):
    在这里插入图片描述
    在这里插入图片描述
    在代码第二段中的23行编译时报错:
    Type mismatch: cannot convert from List to List<? extends Cat>
    因为List赋值给List时会编译出错,因为能赋值给<? extends Cat>的类型,只有Cat和它的子类。因为<? extends Cat>泛型信息表示的是,此笼子(容器)内的全部都是猫,而List笼子(容器)内可能住着毒蛇,鳄鱼、豹猫(猫的天敌)、大型猛禽等动物,不能把它们放同一个笼子(容器)里。 26,27行中,把List赋值给 <? extends T>与<? super T> 都是可以的。

    在第三段代码的36、36、37行均编译出错:
    The method add(capture#1-of ? extends Cat) in the type List<capture#1-of ? extends Cat> is not applicable for the arguments (Animal)
    无法进行add操作,这是因为除null外,任何元素都不能添加进<? extends T>集合中。但<?super Cat>可以往里面添加元素,但只能添加Cat自身即其子类对象,如上面代码中的41、42行。因为猫的笼子中只能关猫,不能关其他动物,如代码中的40行。

    在上面代码中的第四段中,所有的 List<? super T>集合 都能执行get方法返回元素,但是泛型丢失,只能返回object对象,如上面代码中的46、47、48行。List<? extends T>集合 可以返回带类型的元素,但只能返回Cat自身及其父类对象,因为子类对象被擦除了,如代码中的50到54行。

    附:
    第一张图片中的代码

    import java.util.ArrayList;
    import java.util.List;
    public class TestArrayList {
    	public static void main(String[] args) {
    	
    		//第一段:泛型出现之前集合定义方式
    		List a1 =new ArrayList();
    		a1.add(new Object());
    		a1.add(new Integer(10));
    		a1.add(new String("string"));
    		
    		//第二段:把a1引用赋值给a2,(a2与a1的区别是增加了泛型限制)
    		List<Object> a2 =a1;
    		a2.add(new Object());
    		a2.add(new Integer(20));
    		a2.add(new String("string2"));
    		a2.add(25);
    		//List<Object> 接受其他泛型赋值时,会报异常(因为在下面例子中List<Integer>不能转为List<Object>)
    		List<Integer> aint = new ArrayList<Integer>();
    		List<Object> a22 =aint;//Type mismatch: cannot convert from List<Integer> to List<Object>
    		
    		//第三段:把a1引用赋值给a3,(a3与a1的区别是增加了泛型<Integer>)
    		List<Integer> a3 = a1; //此时如果遍历a3则会报类型转换异常ClassCastException
    		a3.add(new Integer(20));
    		//下面两行编译出错,不允许增加非Integer类型进入集合
    		a3.add(new Object());//The method add(Integer) in the type List<Integer> is not applicable for the arguments (Object)
    		a3.add(new String("string2"));
    		
    		//第四段:把a1引用赋值给a4,a4与a1的区别是增加了通配符
    		List<?> a4 = a1;
    		//允许删除和清除元素
    		a4.remove(0);
    		a4.clear();
    		//编译错误,不允许添加任何元素
    		a4.add(new Object());//The method add(capture#3-of ?) in the type List<capture#3-of ?> is not applicable for the arguments (Object)
    		a4.add(new Integer(20));
    		a4.add(new String("string2"));
    	}
    }
    
    

    第二张图片中的代码

    import java.util.ArrayList;
    import java.util.List;
    class Animal{}
    class Cat extends Animal{}
    class Garfield extends Cat{}
    
    //用动物,猫,加菲猫的继承关系说明extends与super在集合中的意义
    public class AnimalCatGarfield {
    	public static void main(String[] args) {
    		//第一段:声明第三个依次继承的集合:Object>动物>猫>加菲猫  三个泛型集合可以理解为三个不同的笼子
    		List<Animal> animal = new ArrayList<Animal>();        //动物
    		List<Cat> cat = new ArrayList<Cat>();				  //猫
    		List<Garfield> garfield = new ArrayList<Garfield>();  //加菲猫
    		
    		animal.add(new Animal());
    		cat.add(new Cat());
    		garfield.add(new Garfield());
    		
    		//第二段:测试赋值操作  以Cat为核心,因为它既有子类又有父类
    		//下行编译出错。只能赋值Cat或Cat子类集合
    		List<? extends Cat> extendsCatFromAnimal = animal;
    		List<? super Cat> superCatFromAnimal = animal;
    		
    		List<? extends Cat> extendsCatFromCat = cat;
    		List<? super Cat> superCatFromCat = cat;
    		
    		List<? extends Cat> extendsCatFromGarfield = garfield;
    		//下行编译出错。只能赋值Cat或着Cat父类集合
    		List<? super Cat> superCatFromGarfield = garfield;
    		
    		//第三段:测试add方法
    		//下面三行中所有的<? extends T>都无法进行add操作,编译出错
    		extendsCatFromCat.add(new Animal());
    		extendsCatFromCat.add(new Cat());
    		extendsCatFromCat.add(new Garfield());
    		
    		//下行编译出错。只能添加Cat或者Cat的子类集合。
    		superCatFromCat.add(new Animal());
    		superCatFromCat.add(new Cat());
    		superCatFromCat.add(new Garfield());
    		
    		//第四段:测试get方法
    		//所有的super操作能够返回元素,但是泛型丢失,只能返回object对象
    		Object object1 = superCatFromCat.get(0);
    		Animal object = superCatFromCat.get(0);//Type mismatch: cannot convert from capture#8-of ? super Cat to Animal
    		Cat object3 = superCatFromCat.get(0);//
    		//以下extends操作能够返回元素
    		Animal catExtends3 = extendsCatFromCat.get(0);
    		Object catExtends2 = extendsCatFromCat.get(0);
    		Cat catExtends1 = extendsCatFromCat.get(0);
    		//下行编译错误。虽然Cat集合从Garfield赋值而来,但类型擦除后,是不知道的
    		Garfield cat2 = extendsCatFromGarfield.get(0);
    	}
    }
    
    
  • 相关阅读:
    2015531 网络攻防 Exp1 PC平台逆向破解(5)M
    2017-2018-1 20155331 嵌入式C语言
    20155330 《网络对抗》 Exp9 web安全基础实践
    20155330 《网络对抗》 Exp8 Web基础
    20155330 《网络对抗》 Exp7 网络欺诈防范
    20155330 《网络对抗》 Exp6 信息搜集与漏洞扫描
    20155330 《网络对抗》 Exp5 MSF基础应用
    20155330 《网络攻防》 Exp4 恶意代码分析
    20155330 《网络攻防》 Exp3 免杀原理与实践
    20155330 《网络对抗》 Exp2 后门原理与实践
  • 原文地址:https://www.cnblogs.com/minghaiJ/p/11259346.html
Copyright © 2011-2022 走看看