java泛型-通配符
通配符
考虑一个编程问题:打印出一个集合的所有的元素,
方法一:
void printCollection(Collection c) { Iterator i = c.iterator(); for (k = 0; k < c.size(); k++) { System.out.println(i.next()); } }
方法二:
void printCollection(Collection
现在问题来了!方法二的使用范围比方法一的适用范围要小,为什么呢?因为方法一它的参数是Collection c 呀,它可以接受任意类型的Collection.而方法二,它只能接受Collection
那我们有没有一个接受任意类型的超级泛型集合呢?
是的,就是Collection<?>, 它可以和任意类型的泛型集合相匹配。如下是我们改进下的方法二:
void printCollection(Collection<?> c) { for (Object e : c) { System.out.println(e); } }
现在,我们就可以使用这个方法二,去接受Collection
Collection<?> c = new ArrayList
c.add(new Object()); // Compile time error
因为我们不知道集合C里面是存的哪种类型,C可能是 Collection
有边界的通配符
1.考虑一个简单画图程序,它能画方形,圆形等。代码如下:
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) { ... } } /**
These classes can be drawn on a canvas:
*/ public class Canvas { public void draw(Shape s) { s.draw(this); }
public void drawAll(Listshapes) {
for (Shape s: shapes) {
s.draw(this);
}
}
注意到Canvas类中的drawAll方法,我们书写这个方法的目的是:让他接受任何类型的shape集合(包括ArrayList
Listlist = new ArrayList (); drawAll(list)//编译错误。理由前面说过了。
现在,我们改进drawAll方法,如下:
public void drawAll(List<? extends Shape> shapes) { ... }
那么这个时候我们的方法就实现了我们上述的目的了,List<? extends Shape> 是可以接受shape本身,或者shape任意子类的List集合的。
其中 ? 代表着未知 ,在这个列子中,?可以代表shape的子类(如Rectangle,Circle),或者shape本身。我们称这样的为“上边界的集合”。
2.再看下面代码,如下:
public void addRectangle(List<? extends Shape> shapes) { // Compile-time error! shapes.add(0, new Rectangle()); }
上面操作不被允许的,
我们知道shapes形参集合可能是Collection或者Collection, 是不确定集合
假设shapes是Collection,那上面的操作明显是错的嘛,因为Circle集合里面不能存Rectangle的。
但这个集合是可以“取”的,就是说 Shape shape = shapes.get(0) 是被认可的,理由简单:shapes存的肯定都是shape或shape的子类,那这种赋值操作当然没问题的了。
总而言之,一个集合你不确定它是哪种类型的集合,你就不能“冒失”的向里面添加东西。
3,考虑这个集合List<? super Rectangle>
这个集合是叫做“下边界的集合” ,它是接受以Rectangle本身,或者Rectangle父类为泛型的集合,是不确定集合。注意如下代码:
List<? super Rectangle> c = new ArrayList(); c.add(new Rectangle());//这是编译通过的。
为什么它能添加!!!,不是说不能确定c是哪种集合吗?
对,但也不对,
对的地方在于 集合C 可能是ArrayList
不对的地方是,有一点是可以确定的,就是集合C 存的东西 都是 Rectangle 的父类 或者 Rectangle本身。考虑如下代码:
Listlist = new ArrayList (); list.add(new Ractangle());//这是可行的。 List list = new ArrayList (); list.add(new Ractangle());//这是也是可行的。
如此,我们总可以向集合C 存 Rectangle实例,能存 Rectangle实例,或者Rectangle子类。
但是不能“直接取直接赋值 Rectangle r = c.get(0) ", 因为 从集合C取的东西,谁知道 是Rectangle实例,还是 Object实例。