未整理。

第五章泛型

2020-03-11  本文已影响0人  后来丶_a24d

目录


泛型

不要使用原始类型

消除非检查警告

@SuppressWarnings("unchecked") T[] result =
            (T[]) Arrays.copyOf(elements, size, a.getClass());
retur result;

列表优于数组

// 运行时报错
Object[] objectArray = new Long[1];
objectArray[0] = "I don't fit in"; // Throws ArrayStoreException

// 无法编译通过
List<Object> ol = new ArrayList<Long>(); // Incompatible types
ol.add("I don't fit in");

优先考虑泛型

public class Stack {
    private Object[] elements;
    private int size = 0;
    private static final int DEFAULT_INITIAL_CAPACITY = 16;

    public Stack() {
        elements = new Object[DEFAULT_INITIAL_CAPACITY];
    }

    public void push(Object e) {
        ensureCapacity();
        elements[size++] = e;
    }

    public Object pop() {
        if (size == 0)
            throw new EmptyStackException();
        Object result = elements[--size];
        elements[size] = null; // Eliminate obsolete reference
        return result;
    }

优先使用泛型方法

// 这种会有警告
public static Set union(Set s1, Set s2) {

    Set result = new HashSet(s1);

    result.addAll(s2);

    return result;
}

//这种是安全的
public static <E> Set<E> union(Set<E> s1, Set<E> s2) {

    Set<E> result = new HashSet<>(s1);

    result.addAll(s2);

    return result;

}
public static <E extends Comparable<E>> E max(Collection<E> c) {
    if (c.isEmpty()) throw new IllegalArgumentException("Empty collection");
    E result = null;
    for (E e : c){
        if (result == null || e.compareTo(result) > 0){
            result = Objects.requireNonNull(e);
        }
    }
    return result;
}

使用限定通配符来增加API的灵活性

//考虑以下这种,如果pushAll方法是public void pushAll(Iterable<E> src) 则会报错,因为参数化类型是不变的。
Stack<Number> numberStack = new Stack<>();

Iterable<Integer> integers = ... ;

numberStack.pushAll(integers);

//可以变成这种, 这样增加灵活性。生成栈使用的E实例使用extend
public void pushAll(Iterable<? extends E> src)
// 消费栈使用的E实例使用super 
public void popAll(Collection<? super E> dst)
// 所有Comparable和Comparator都是消费者
// 无界类型参数
public static <E> void swap(List<E> list, int i, int j); 

// 无界通配符:该方式优于上一个方式,但是由于无界通配符类型无法修改,即需要借助helper进行修改,但这对于调用者无需关心。
public static void swap(List<?> list, int i, int j) { 
    swapHelper(list, i, j);
}

private static <E> void swapHelper(List<E> list, int i, int j) { 
    list.set(i, list.set(j, list.get(i)));
}
汇总
  1. 上边界类型通配符(<? extends 父类型>):因为可以确定父类型,所以可以以父类型去获取数据(向上转型)。但是不能写入数据。
  2. 下边界类型通配符(<? super 子类型>):因为可以确定最小类型,所以可以以最小类型去写入数据(向上转型)。而不能获取数据。
  3. 无边界类型通配符(<?>) 等同于 上边界通配符<? extends Object>,所以可以以Object类去获取数据。List list 相当于List<Object> list

合理地结合泛型和可变参数

优先考虑类型安全的异构容器

public class Favorites {
    private Map<Class<?>, Object> favorites = new HashMap<>();

    public <T> void putFavorite(Class<T> type, T instance) {
        favorites.put(Objects.requireNonNull(type), instance);
    }

    public <T> T getFavorite(Class<T> type) {
        return type.cast(favorites.get(type));
    }
}

参考文章

上一篇下一篇

猜你喜欢

热点阅读