如同类一样,方法也可以加入泛型,尤其是静态工具类方法。Collections 骨架类中,全用到了泛型方法。书中例子
public static Set union(Set s1, Set s2) {
Set result = new HashSet(s1);
result.addAll(s2);
return result;
}
这个方法可以编译,但是有两条警告,Unchecked call to HashSet(Collection<? extends E>) as a member of raw type HashSet , 为了清除警告,保证方法是安全的,需要将方法修改参数的类型声明,保证从传入的参数到生成的集合,类型是一致的,我们可以增加 <E>, 这个是通用的,增加后,变为
public static <E> Set union(Set<E> s1, Set<E> s2) {
Set result = new HashSet(s1);
result.addAll(s2);
return result;
}
简单的增加泛型,就是这样,要在参数中添加泛型,同时也要在返回参数类型处增加泛型,缺一不可。这个方法可以被调用,比如说 s1 和 s2 都是 String 类型的集合,我们可以调用,这时会产生新的集合,
public static void main(String[] args) {
Set<String> a = new HashSet<String>();
a.add("a");
Set<String> b = new HashSet<String>();
b.add("b");
Set<String> set = union(a, b);
System.out.println(set);
}
打印的结果是 [a, b] 。 这个方法可以使用,但有个局限,就是参数类型必须一致,返回的类型也与参数的类型一样。 Number 是 Integer 的基类类,Set<Number> s1 ,Set<Integer> s2,理论上说,基类集合能装子类对象, 但是我们调用上述方法,编译会报错,怎么办? 就需要用到 有限制的通配符,可以提高方法的灵活性。 泛型的特点是编译器调用,编译器通过参数类型推倒返回值的类型。 第一个案例中, 由于调用的两个集合都是 <String> 类型,所以知道类型E 就是 String,返回的类型也是Set<String> 类型,这个叫做类型推导。平时创建对象,需要我们自己去new,同时传入对象类型,我们 Map<String, Set<String>> map = new HashMap<String, Set<String>>(); 很麻烦,我们可以自定义个静态方法,来以不变应万变,
public static <K, V> HashMap<K, V> newHashMap() {
return new HashMap<K, V>();
}
这种方法比较有效,说句题外话,这种写法是java 1.8 之前的写法,在1.8时,java改进了,可以直接 Map<String, Set<String>> map = new HashMap<>(); 自动包含了类型推导。
泛型有时会和函数对象一块使用,书中给了个例子,咱们在这举另外一个常见的例子,
public interface Comparable<T>{
public int compareTo(T o);
}
我们经常会用到它来排序,之前提到过,如果大量使用,可以创建一个静态对象,缓存到内存中,避免被大量创建。
书中的例子,咱么可以用 Comparable 来重复写一遍
private static Comparable<Object> INSTAGE_COMPARABLE = new Comparable<Object>() {
@Override
public int compareTo(Object o) {
return o.hashCode();
}
};
public static <T> Comparable<T> compare(){
return (Comparable<T>) INSTAGE_COMPARABLE;
}
不过,如果我们调用compare() 方法,获取该对象,用它来作为排序标准,比较 hashCode 值,这是一种应用。
许多方法都带有一个实现 Comparable 接口的元素类表,进行排序,我们可以这么写
public static <T extends Comparable<T>> T max(List<T> list) {
}
泛型里面多了个东西,继承方法, 类型限制 <T extends Comparable<T>> 可以理解为 每一个 T 类型的对象,都必须要实现 Comparable 接口,这样,就可以通过 Comparable 接口中的方法返回值,来进行比较大小了
public static <T extends Comparable<T>> T max(List<T> list) {
Iterator<T> iterator = list.iterator();
T result = iterator.next();
T t ;
while (iterator.hasNext()){
t = iterator.next();
if(t.compareTo(result) > 0){
result = t;
}
}
return result;
}
我们知道,我们用 t.compareTo(result) > 0 这个比较功能时,对象必须是实现 Comparable 接口的。 上述基本上满足功能,但是还不完美,还有缺陷, 我们发现Collections 中也有用到Comparable ,比如排序,
public static <T extends Comparable<? super T>> void sort(List<T> list) {
}
细心的法相了,Comparable<? super T> 里面又多了个关键字,为什么这么写呢,因为这样写灵活性和匹配性更高,下章再继续讲解。