博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
java泛型中,上下界通配符(<? extends T>跟<? super T>)
阅读量:7014 次
发布时间:2019-06-28

本文共 3979 字,大约阅读时间需要 13 分钟。

hot3.png

背景介绍:java中的泛型,是在java5.0后才引用的,泛型,可以让我们更安全的操作容器,而不用担心出现让人非常不快的ClassCastException异常,但是泛型没有多态的概念,Sun的那群大脑袋,就想到了一个解决办法,就是上界通配符<? extends T>,跟下界通配符(<? super T>),下面就介绍一下个人对它的理解吧,

 

首先,我们先定义几个类:

Leve2class Food{}Leve2class Fruit{}class Meat{}Leve3class Apple{}class WaterMelon{}

 

继承关系图如下:

002722_Noz9_2278977.png

 

然后我们定义2个不使用通配符的方法:

/**	 * 不使用上界通配符	 */	public static void isUpMethod(List
list){ } /** * 不使用下界通配符 */ public static void isDownMethod(List
list){ }

 

接着,我们使用2个List,放函数里面存参数:

List
apples = new ArrayList<>(); apples.add(new Apple()); apples.add(new Apple()); apples.add(new Apple()); //两个方法编译会报错 //isUpMethod(apples); //isDownMethod(apples); List
fruits = new ArrayList<>(); fruits.add(new Fruit()); fruits.add(new Fruit()); fruits.add(new Fruit()); //编译通过 isUpMethod(fruits); isDownMethod(fruits);

有同学就会问了,List的泛型指定了Fruit类型,另外一个List泛型指定了Apple肯定编译不过去啊,但是,别忘了,Apple是Fruit的子类,我们理解中 Fruit fruit = new Apple();是可行的,因为java的多态;

但是,泛型是没有多态的,它可不认为Apple是Fruit的子类,如果这样的话,为代码重用代码很大的麻烦,因为泛型只是编译级别,在运行期间,泛型是会擦除的;

PS:指定泛型集合后,往内添加的元素可以是Fruit的子类,因为会自动向上转型,触发多态

如果想isUpdownMethod或者isDownMethod函数,接收其泛型类的子类或者父类,这时候,我们就可以使用上界通配符了<? extends Fruit>跟下界通配符<? super Fruit>

 

我们定义一个如下函数:

/**	 * 上界通配符	 */	public static void upMethod(List
list){ //编译报错 //使用通配符后,不能在往集合类中添加元素 //list.add(); //使用通配符后,是可以取出元素的 //所有取出的元素,都是上界父类元素 Fruit fruit = list.get(0); } /** * 下界通配符 */ public static void downMethod(List
list){ //下界通配符可以往容器内添加元素 //但是有限制,必须是Fruit的子类或者本身,父类是添加不进去的 list.add(new Apple()); //取出元素的类型都为Object Object object = list.get(0); }

然后,我们试试使用往函数类传输LIST集合泛型指定是子类的集合:

List
apples = new ArrayList<>(); apples.add(new Apple()); apples.add(new Apple()); apples.add(new Apple()); List
fruits = new ArrayList<>(); fruits.add(new Fruit()); fruits.add(new Fruit()); fruits.add(new Fruit()); List
foods = new ArrayList<>(); foods.add(new Food()); foods.add(new Food()); foods.add(new Food()); //编译通过 upMethod(apples); upMethod(fruits); //编译通过 downMethod(fruits); downMethod(foods);

 

 

上界通配符<? extends Fruit>

简介:

  •     上界通配符中的上界,指的是泛型内的类型,最高是Fruit类,最低不限,只要是继承了Fruit类,都可以通过编译,这也就是为什么叫 "上界",最高类型就是Fruit类          

描述:

  • 在upMethod函数中,使用上界通配符后,限定了条件,传参对象的泛型,必须是Fruit类或者其子类,才能通过编译,否则,编译就会失败,

  • 特性:
    • 在使用上界通配符后,我们不能在往集合内添加元素,那是因为,虽然指定了泛型的类型是Fruit类或者其子类,但是Fruit类可能并不止一个子类,可能除了Apple外还有Banana或者Watermelon类,如果你传递进来的是Apple集合,但是往里面添加Banana,这种情况下,往外取元素的时候很大的可能性会出现异常,因为取出的元素不是Apple而是Banana.所以,避免出现这种情况,使用上界通配符后,是不能再往集合内添加元素,
    • 可以往外取元素,所有取出的元素都是Fruit类,因为,编译器只知道是Fruit的子类,但是却不知道是具体哪个子类,所以取出的元素是最高层的类,也就是Fruit类

 

 

---------------------------------分割线----------------------------------------

 

 

下界通配符<? super Fruit>描述:

简介:

  •     下界通配符中的下界,指的是泛型内的类型,最低是Fruit类,最高到超类Object,只要是Fruit的父类,都可以通过编译,这也就是为什么叫 "下界",因为最低是Fruit类       

描述:

  • 在downMethod函数中,使用下界通配符后,限定了条件,传参对象的泛型,必须是Fruit类或者其父类,才能通过编译,否则,编译就会失败,

  • 特性:
    • 可以往集合内添加元素,但是限制条件是往内添加的元素,必须是Fruit的子类,因为虽然知道是Fruit的基类 但也不知道是往上数多少级的基类 只有Fruit以及它的子类 编译器才能断定能触发多态,
    • 可以往外取元素,但是取出来的元素都是Object,因为取出来的有可能是Food,比Fruit范围大,不能赋值给Fruit对象。只有Object可以,因为没有类比Object大。

 

 

---------------------------------分割线----------------------------------------

有人可能会问,为什么使用上界通配符后,不能往里存元素了,但是使用下界通配符能往里面存元素,原因如下:

  1. 上界通配符指定了上限,最高就是Fruit类,往里存元素,不是Fruit就是其子类啊,理论上是可以往内存的,那是因为使用上界通配符后,虽然有上限,但是没有下限啊,编译器,只知道是Fruit类或者是Fruit的子类,但是具体是哪个类型的子类,编译器也不知道,为了防止出现类型转换错误,所以,就禁止再往内添加元素(如果是我,我也会这么做,避免出现这样的情况)

  2. 下界通配符能往内存元素是因为下界通配符,规定了最小粒度的下限,是Fruit类.实际上是放松了对元素的类型控制,既然元素是Fruit类的父类,那往里存Fruit子类肯定可以的,因为Fruit的子类,也是其Fruit父类的子类,

  3. 上界通配符<? extends Fruit> 可以看成<?> 类型都不知道,肯定不让往里面添加元素,因为没有下限;也可以看成是一个可以放某种Fruit的集合,不是一个可以放任何Fruit的大杂烩集合
  4. 下界通配符<? super Fruit> 可以看成<Fruit>,确定了类型最低是Fruit,所以可以往内添加元素,但是必须是Fruit或者其子类​​​​​​​;也可以看成是一个可以放任何Fruit的集合

 

---------------------------------分割线----------------------------------------

 

总结:

  •         上界通配符<? extends T> 指的是,引用内的泛型范围,最高是T类,最低不限
    • 可以取元素
    • 不能添加元素
  •         下界通配符<? super T> 指的是,引用内的泛型范围,最低是T类,最高是超类Object
    • 可以取元素,但是取出的元素是Object
    • 可以添加元素,添加的元素,必须是T类或者其子类

 

到这,文章就结束了!

以上,均为本人理解,如果理解错误,欢迎指正

欢迎转载,请注明出处跟作者,谢谢!

 

转载于:https://my.oschina.net/u/2278977/blog/820771

你可能感兴趣的文章
border-style 属性
查看>>
只有iOS开发者,才能看的懂的,斥锁-读写锁-条件锁
查看>>
如何用 Uber JVM Profiler 等可视化工具监控 Spark 应用程序?
查看>>
新技能Get:如何利用HTTP技术提升网页的加载速度
查看>>
拒绝旧国标劣质排插,新国标插线板首选品胜
查看>>
金融业务上云要熟虑 看IBM如何化解难题
查看>>
AT&amp;T将于2018年底在十几个城市推出5G网络
查看>>
品钛在美国上市 魏伟:上市不是锣鼓欢庆 而是起跑发令枪
查看>>
学习Python爬虫真的不难,只需要明白这四个点!
查看>>
新疆国省干线总里程突破2.9万公里
查看>>
国产智轨电车开进“冰城”接受严寒测试 表现良好
查看>>
缓解“钱紧” 央行本周公开市场净投放创两年新高
查看>>
21岁大专学历,刚培训完前端,不造假简历,能找到工作吗?
查看>>
国内首部区块链行业纪录片开播
查看>>
List集合就这么简单【源码剖析】
查看>>
Spring Cloud (十四):Spring Cloud 开源软件都有哪些?
查看>>
前端状态管理与有限状态机
查看>>
读Zepto源码之Data模块
查看>>
Redux助力美团点评前端进阶之路
查看>>
【闭包概念】关于闭包概念不同解读——你可以自己理解。
查看>>