JAVA泛型

2018年6月19日12:03:57 发表评论 389

误区

List<String> ls =​​ new​​ ArrayList<String>();​​ // 1

List<Object> lo = ls;​​ // 2​​ 

lo.add(new​​ Object());​​ // 3

String s = ls.get(0);​​ // 4: Attempts to assign an Object to a String!

上面例子看到第二行的时候,很多人会认为表达式成立,因为我们认为StringObject的子类,那么List<String>也应该是List<Object>的子集合;可看完整段程序,我们又疑惑了,怎么能将Object直接放进去List<String>(这里通过List<Object>访问List<String>),这样的话,List<String>将不再只存放String对象了,这怎么行?因此在程序第二行,编译器会给出错误提示。

PECS

Producer Extends Consumer Super

例子

  • Fruit类和它的派生类Apple

class​​ Fruit​​ { }

class​​ Apple​​ extends​​ Fruit​​ { }

  • 最简单的容器:Plate

class​​ Plate<T> {​​ 

private​​ T item;​​ 

public​​ Plate(T t) {​​ 

 item = t;​​ 

 }​​ 

public​​ void​​ set(T t) {​​ 

 item = t;​​ 

 }​​ 

public​​ T​​ get() {​​ 

return​​ item;​​ 

 }​​ 

}

  • 定义一个水果盘子,逻辑上水果盘子当然可以装苹果,可事实上它却发生了异常。

Plate<Fruit> p =​​ new​​ Plate<Apple>(new​​ Apple()); // error​​ 

Type mismatch: cannot convert from Plate<Apple>​​ to Plate<Fruit>

结论:就算容器装的东西之间有继承关系,但容器之间是没有继承关系的

泛型

上界通配符​​ Upper Bounds Wildcards

Plate<?​​ extends Fruit>

意思是:一个能放水果以及一切是水果派生类的盘子

Plate<? extends Fruit>Plate<Fruit>以及Plate<Apple>的基类

Plate<?​​ extends Fruit> p =​​ new​​ Plate<Apple>(new​​ Apple());

上面的例子是成立的。

https://upload-images.jianshu.io/upload_images/3251891-4aab0685b5c2d4d0.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/600

继承体系图

 

下界通配符​​ Lower Bounds Wildcards

Plate<?​​ super​​ Fruit>

意思是与上界通配符相反的概念:一个能放水果以及一切是水果基类的盘子

Plate<? super Fruit>是Plate<Fruit>的基类,但不是Plate<Apple>的基类。

https://upload-images.jianshu.io/upload_images/3251891-66f55f072aa87e68.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/600

继承体系图

上下界通配符的副作用

边界让Java不同泛型之间的转换更容易,但是也会让容器的部分功能可能失效

上界<? extends T>

造成结果:不能往里存,只能往外取。

<? extends Fruit>会使往盘子里放东西的set( )方法失效。但取东西get( )方法还有效。

对于Plate​​ <? extends Fruit>编译器只知道容器Plate内是Fruit或者它的派生类,但具体是什么类型不知道。用Plate<Apple>赋值给容器以后,容器没有被标上苹果而是标上一个占位符:CAP#1,来表示捕获一个FruitFruit子类,具体是什么类不知道然后无论是想往容器里插入Apple或者Banana或者Fruit编译器都不知道能不能和这个CAP#1匹配,所以都不允许。

 

下界<? super T>

不影响往里存,但往外取只能放在Object对象里

 

<T extends Fruit>与<? extends Fruit>区别

<T extends Fruit>作用于方法或者类上,而​​ <? extends Fruit>​​ 则不可以。

 

 

 

 

https://www.jianshu.com/p/276699764aa2

 

https://www.cnblogs.com/VergiLyn/p/6349601.html

https://segmentfault.com/q/1010000002489030

 

https://garygregory.wordpress.com/2016/11/29/understanding-java-generics-super-and-extends/

 

https://dzone.com/articles/how-do-generic-subtypes-work

http://www.codejava.net/java-core/collections/how-to-write-generic-classes-and-methods-in-java

https://blog.csdn.net/qq_27093465/article/details/73249434

 

https://www.cnblogs.com/Michaelwjw/p/5881875.html

 

weinxin
微信公众号
分享IT信息技术、北海生活的网站。提供北海本地化的信息技术服务。
连线北海

发表评论

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen: