JAVA泛型
考虑写一个方法,它用一个Object的数组和一个collection作为参数,完成把数组中所有object放入collection中的功能。
下面是第一次尝试:
Java代码
static void fromArrayToCollection(Object[] a, Collection<?> c) {
for (Object o : a) {
c.add(o); // 编译期错误
}
}
现在,你应该能够学会避免初学者试图使用Collection<Object>作为集合参数类型的错误了。或许你已经意识到使用 Collection<?>也不能工作。会议一下,你不能把对象放进一个未知类型的集合中去。
解决这个问题的办法是使用generic methods。就像类型声明,方法的声明也可以被泛型化——就是说,带有一个或者多个类型参数。
Java代码
Static <T> void fromArrayToCollection(T[] a, Collection<T> c) {
for (T o : a) {
c.add(o); // corret
}
}
注意,我们并没有传送真实类型参数(actual type argument)给一个泛型方法。编译器根据实参为我们推断类型参数的值。它通常推断出能使调用类型正确的最明确的类型参数(原文是:It will generally infer the most specific type argument that will make the call type-correct.)。
现在有一个问题:我们应该什么时候使用泛型方法,又什么时候使用通配符类型呢?
为了理解答案,让我们先看看Collection库中的几个方法。
Java代码
public inte易做图ce Collection<E> {
boolean containsAll(Collection<?> c);
boolean addAll(Collection<? extends E> c);
}
我们也可以使用泛型方法来代替:
Java代码
public inte易做图ce Collection<E> {
<T> boolean containsAll(Collection<T> c);
<T extends E> boolean addAll(Collection<T> c);
// hey, type variables can have bounds too!
}
但是,在 containsAll 和 addAll中,类型参数T 都只使用一次。返回值的类型既不依赖于类型参数(type parameter)也不依赖于方法的其他参数(这里,只有简单的一个参数)。这告诉我们类型参数(type argument)被用作多态(polymorphism),它唯一的效果是允许在不同的调用点,可以使用多种实参类型(actual argument)。如果是这种情况,应该使用通配符。通配符就是被设计用来支持灵活的子类化的,这是我们在这里要强调的。
泛型函数允许类型参数被用来表示方法的一个或多个参数之间的依赖关系,或者参数与其返回值的依赖关系。如果没有这样的依赖关系,不应该使用泛型方法。
补充:软件开发 , Java ,