java泛型通配符
2016-07-09 14:36
253 查看
考虑到常规打印集合所有元素的问题,然而你将写一个比较好的版本(jdk1.5以前)
哪什么才是任何集合类型的超类型?它应该被写成Collection<?>(表示集合类型未知), 这样可以匹配任何类型.
这就是所谓的通配符类型,原因很明显。我们可以这样写
由于我们不知道c代表的是什么元素,我们不能向集合添加对象。add()方法里面的参数为E,也是集合类型,当使用?作为参数是,它代表的类型是未知的,我们通过添加任何参数必须是这个未知类型的子类型。因为我们不知道那是什么类型的,我们不能传递任何东西。唯一的例外是null,它是每一个类型的成员。
另一方面,获得一个List<?>,我们可以通过调用get()方法获取和使用元素,这个元素的类型是未知的,但是我们总知道它是一个对象,将get()的结果赋值给Object类型的变量时安全的把它作为其中类型对象期望的参数。
边界通配符
考虑一个简单的画图一样,能够花的图形例如矩形和圆形。类的继承结构如下:
这些类都能在画布上画图:
任何绘图通常含有多种形状的。假设他们表示为一个列表,这将是方便的在Canvas的方法,吸引了所有这些:
现在,类型规则说drawAll()只能算得上准确形状的名单:它不能,例如,算得上一个List <Circle>。这是不幸的,因为所有的方法不会被从列表中读出的形状,所以它也可以同样可以在一个List <Circle>调用。我们真正需要的是接受任何一种形状的列表的方法:
这是聪明的,但是非常重要的地方:我们是用List<? extends Shape>替换了List<Shape>。现在drawAll() 可以接受Shape的子类类型,如果我们想使用,我们现在就可以使用List<Circle>调用。
List<? extends Shape> 是一个边界通配的示例。而这个?代表的未知类型,就像以前看到的通配符。然而,例如,我们虽然知道那个未知类型是Shape的子类型。(Note:它可能是自身或它的子类,不需要字面继承Shape)我们说Shape是通配符的上界。
还有就是,像往常一样,价格要支付使用通配符的灵活性。价格是它现在是非法写入形状的方法。例如,这是不允许的:
你应该能够找出为什么上面的代码是不允许的。shapes.add()的第二个参数是什么?继承Shape--一个Shape的未知类型。因为我们不知道它的类型是什么,如果它是一个Rectangle的父类型,它可能或不可能是一个父类型,因此它添加Rectangle是不安全的。
原文链接:https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
void printCollection(Collection c) { Iterator i = c.iterator(); for (k = 0; k < c.size(); k++) { System.out.println(i.next()); } }然而有一个幼稚的想法去使用泛型(使用新的for)
void printCollection(Collection<Object> c) { for (Object e : c) { System.out.println(e); } }问题是,这种新的版本的使用比旧版本使用少得多。其中,作为旧代码可以与任何种类的集合作为参数调用,而新的代码只能使用Collection<Object>,其中,因为我们刚刚的演示,不是所有类型的集合的超类型
哪什么才是任何集合类型的超类型?它应该被写成Collection<?>(表示集合类型未知), 这样可以匹配任何类型.
这就是所谓的通配符类型,原因很明显。我们可以这样写
void printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e); } }然而,现在我们调用任何集合类型。注意printCollection()的内部我们可以一直读取元素并赋给Object类型,这是安全的。因为任何集合的实际类型,它包含对象。它不安全的是不能任意添加元素。
Collection<?> c = new ArrayList<String>(); c.add(new Object()); // Compile time error c.add(null);//OK because null is any type
由于我们不知道c代表的是什么元素,我们不能向集合添加对象。add()方法里面的参数为E,也是集合类型,当使用?作为参数是,它代表的类型是未知的,我们通过添加任何参数必须是这个未知类型的子类型。因为我们不知道那是什么类型的,我们不能传递任何东西。唯一的例外是null,它是每一个类型的成员。
另一方面,获得一个List<?>,我们可以通过调用get()方法获取和使用元素,这个元素的类型是未知的,但是我们总知道它是一个对象,将get()的结果赋值给Object类型的变量时安全的把它作为其中类型对象期望的参数。
边界通配符
考虑一个简单的画图一样,能够花的图形例如矩形和圆形。类的继承结构如下:
public abstract class Shape { public abstract void draw(Canvas c); } public class Circle extends Shape { private int x, y, radius; public void draw(Canvas c) { ... } } public class Rectangle extends Shape { private int x, y, width, height; public void draw(Canvas c) { ... } }
这些类都能在画布上画图:
public class Canvas { public void draw(Shape s) { s.draw(this); } }
任何绘图通常含有多种形状的。假设他们表示为一个列表,这将是方便的在Canvas的方法,吸引了所有这些:
public void drawAll(List<Shape> shapes) { for (Shape s: shapes) { s.draw(this); } }
现在,类型规则说drawAll()只能算得上准确形状的名单:它不能,例如,算得上一个List <Circle>。这是不幸的,因为所有的方法不会被从列表中读出的形状,所以它也可以同样可以在一个List <Circle>调用。我们真正需要的是接受任何一种形状的列表的方法:
public void drawAll(List<? extends Shape> shapes) { ... }
这是聪明的,但是非常重要的地方:我们是用List<? extends Shape>替换了List<Shape>。现在drawAll() 可以接受Shape的子类类型,如果我们想使用,我们现在就可以使用List<Circle>调用。
List<? extends Shape> 是一个边界通配的示例。而这个?代表的未知类型,就像以前看到的通配符。然而,例如,我们虽然知道那个未知类型是Shape的子类型。(Note:它可能是自身或它的子类,不需要字面继承Shape)我们说Shape是通配符的上界。
还有就是,像往常一样,价格要支付使用通配符的灵活性。价格是它现在是非法写入形状的方法。例如,这是不允许的:
public void addRectangle(List<? extends Shape> shapes) { // Compile-time error! shapes.add(0, new Rectangle()); }
你应该能够找出为什么上面的代码是不允许的。shapes.add()的第二个参数是什么?继承Shape--一个Shape的未知类型。因为我们不知道它的类型是什么,如果它是一个Rectangle的父类型,它可能或不可能是一个父类型,因此它添加Rectangle是不安全的。
原文链接:https://docs.oracle.com/javase/tutorial/extra/generics/wildcards.html
相关文章推荐
- java 图片处理灰度化
- 《Spring设计思想》AOP设计基本原理
- Java正则表达式(详解)
- 基于配置的springmvc流程分析
- 浅谈JavaEE中的JDBC模板类的封装实现以及合理的建立项目包结构(一)
- maven搭建nexus私服在myeclipse中的使用
- java实现数字螺旋矩阵
- Jfinal 集成spring 、cxf 做webService服务
- 新闻案例
- CXF WebService整合Spring
- 关于java高并发的一些感悟和经验已经我自己找的资料
- PL/SQL实现JAVA中的split()方法的小例子
- 消息中间件activemq-5.13.0整合spring
- Spring 定时器配置 基于配置文件 (使用 Spring3.2 、 quartz-1.6.5)
- java基础知识回顾---单例模式的三种实现
- ubuntu安装Eclipse无图标(手动创建软件图标)
- Java----多线程知识点归纳(概念)
- 二叉树java笔试操作总结
- java链表编程题总结
- springmvc 返回json数据给前台jsp页面展示