在大多数情况下泛型方法可以用来代替通配符,例如对于集合框架中的Collection接口的两个方法定义:
public interface Collection<E>{
boolean containsAll(Collection<?> c);
boolean addAll(Collection<?Exends E> c);
}
在上面的集合中两个方法的形式参数都是采用了通配符的形式,那么此时也可以使用泛型方法来代替类型通配符的使用:
public interface Collection<E>{
boolean<T> containsAll(Collection<T> c);
boolean<T extends E> addAll(Collection<T> c);
}
上面的方法使用了<T extends E> 泛型形式,其作用是定义类型形参时指定其上限.
特别注意的是:在这两个方法中,类型形参T只使用了一次,类型形参T的唯一效果是可以在不同的调用点传入不同的实际类型.对于这种情况,应该使用通配符.
泛型方法允许类型形参被用来表示方法的一个或多个参数之间的类型类型依赖关系,或者方法返回值与参数之间的类型依赖关系.如果没有这样的类型依赖关系,不应该使用泛型方法.
如果需要,也可以同时使用泛型方法和通配符.例如Collections 类中的copy()方法:
class Collections{
public static<T>void copy(List<T>d,LIst<?Extends T>s){
//代码实现
}
}
在 copy()方法中,两个参数之间存在明显的依赖关系,即从源程序中赋值出来的元素,必须要复制到目标程序中,所以集合元素的类型只能是目标集合元素的类型本身或是其子类的类型.但是在JDK中表示源程序的S形参使用的是通配符,而不是泛型方法,是因为该方法无需向源程序集合中添加元素,也无需改变源程序集合里的元素,所以可以使用类型通配符,无需使用泛型方法.
对于上面的代码,也可以采用泛型方法,而不使用通配符,修改后代码如下:
class Collections{
public static<T>void copy(List<T>d,LIst<S>s){
//代码实现
}
}
这上方法签名可以代替前面的方法签名,但需要注意上面的类型形参S,它也是仅用了一次,没有其它参数类型,方法返回值类型依赖于它,那类型形参S就没有必要存在.即可以用通配符来代替S
使用通配符比显示声明类型形参更加清晰准确,所以在可能的情况下使用通配符更好.
类型通配符与显示志明类型形参还有一个显著的区别:
类型通配符即可以方法签名中定义形参的类型,也可以于定义变量的类型,但泛型方法中类型形参必须在对应方法中显示声明.
|