我们下一个话题,先由这个引起:我们说过,如果List
List<Circle> circleList = new List<Circle>();
List<Shape> shapeList = circleList; //错误
shapeList.add(new Shape());
circleList.iterator().next(); //出错。
List<Shape> shapeList = circleList; //错误
shapeList.add(new Shape());
circleList.iterator().next(); //出错。
那么List确实是List
List<Circle> circleList = new List<Circle>();
List<?> list= circleList; //正确
list.add(new Shape()); //错误
List<?> list= circleList; //正确
list.add(new Shape()); //错误
为什么list不能加新元素?因为list里的元素类型已经定义好了,是?,不是任何类型,所以不能加入任何类型的元素。
所以如下方法是不能使用的:
static void fromArrayToCollection(Object[] a, Collection<?> c) {
for (Object o : a) {
c.add(o); // compile time error 因为c不能加入元素
}
}
for (Object o : a) {
c.add(o); // compile time error 因为c不能加入元素
}
}
但是我们想要在List里加入元素如何弄呢?一个例子概括如下:
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // correct
}
}
for (T o : a) {
c.add(o); // correct
}
}
那么这样,c这个Collection就能加入东西了,加入的东西必须是T类,看例子:
Object[] oa = new Object[100];
Collection<Object> co = new ArrayList<Object>();
fromArrayToCollection(oa, co);// T inferred to be Object
String[] sa = new String[100];
Collection<String> cs = new ArrayList<String>();
fromArrayToCollection(sa, cs);// T inferred to be String
fromArrayToCollection(sa, co);// T inferred to be Object
Integer[] ia = new Integer[100];
Float[] fa = new Float[100];
Number[] na = new Number[100];
Collection<Number> cn = new ArrayList<Number>();
fromArrayToCollection(ia, cn);// T inferred to be Number
fromArrayToCollection(fa, cn);// T inferred to be Number
fromArrayToCollection(na, cn);// T inferred to be Number
fromArrayToCollection(na, co);// T inferred to be Object
fromArrayToCollection(na, cs);// compile-time error
Collection<Object> co = new ArrayList<Object>();
fromArrayToCollection(oa, co);// T inferred to be Object
String[] sa = new String[100];
Collection<String> cs = new ArrayList<String>();
fromArrayToCollection(sa, cs);// T inferred to be String
fromArrayToCollection(sa, co);// T inferred to be Object
Integer[] ia = new Integer[100];
Float[] fa = new Float[100];
Number[] na = new Number[100];
Collection<Number> cn = new ArrayList<Number>();
fromArrayToCollection(ia, cn);// T inferred to be Number
fromArrayToCollection(fa, cn);// T inferred to be Number
fromArrayToCollection(na, cn);// T inferred to be Number
fromArrayToCollection(na, co);// T inferred to be Object
fromArrayToCollection(na, cs);// compile-time error
到现在为止,上面一共讲了两个jdk1.5中新的事物
List<? extends Parent> list = new LinkedList<Child>(); // wildcards
static <T> void fromArrayToCollection(T[] a, Collection<T> c)
static <T> void fromArrayToCollection(T[] a, Collection<T> c)
那么看下面两个例子,他们做的事情都是一样的,但是分别用了这两个方法:
interface Collection<E> {
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E) c);
}
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
}
public boolean containsAll(Collection<?> c);
public boolean addAll(Collection<? extends E) c);
}
interface Collection<E> {
public <T> boolean containsAll(Collection<T> c);
public <T extends E> boolean addAll(Collection<T> c);
}
他们都做两件事:判断任意类的容器是不是在本身这容器里。加入E子类的容器到本身的容器里。
也可以同时都用上两个新东西:
class Collection {
public static <T> void copy(List<T> dest, List<? extends T> src){}
}
public static <T> void copy(List<T> dest, List<? extends T> src){}
}
或者写成
class Collection {
public static <T,S extends T> void copy(List<T> dest, List<S> src){}
}
public static <T,S extends T> void copy(List<T> dest, List<S> src){}
}
作为总结这两个新的java特性,举出一个复杂例子:
static List<List<? extends Shape>> history = new ArrayList<List<? extends Shape>>();
public void drawAll(List<? extends Shape> shapes) {
history.addLast(shapes);
for(Shape s : shape) {
s.draw(this);
}
}
public void drawAll(List<? extends Shape> shapes) {
history.addLast(shapes);
for(Shape s : shape) {
s.draw(this);
}
}