术语 | 例子 |
---|---|
参数化类型(Parameterized type) | List<String> |
实际类型参数(Actual type parameter) | String |
泛型类型(Generic type) | List<E> |
形式类型参数(Formal type parameter) | E |
无限制通配符类型(Unbounded wildcard type) | List<?> |
原始类型(Raw type) | List |
有限制类型参数(Bounded type parameter) | <E extends Number> |
递归类型限制(Recursive type bound) | <T extends Comparable<T>> |
有限制通配符类型(Bounded wildcard type) | List<? extends Number> |
泛型方法(Generic method) | static <E> List< E > asList(E[] a) |
类型令牌(Type token) | String.class |
// 按照这么写并不会报错(List内部由一个Object数组维护),可是使用上很容易出错。 List list = new ArrayList(); list.add("Hello"); list.add(100);
public <T> T[] toArray(T[] a) { if (a.length < size) { @SuppressWarnings("unchecked") T[] result = (T[]) Arrays.copyOf(elements, size, a.getClass()); return result; } System.arraycopy(elements, 0, a, 0, size); if (a.length > size) a[size] = null; return a; }
// 运行时报错 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");
数组在运行时才知道并检查元素类型。html
E,List<E>,和List<String>这些类型在技术上都被称为不可具化类型,即运行时展现信息比编译时展现信息要少的类型。java
public class Stack<E> { private E[] elements; private int size = 0; private static final int DEFAULT_INITIAL_CAPACITY = 16; // The elements array will contain only E instances from push(E). // This is sufficient to ensure type safety, but the runtime // type of the array won't be E[]; it will always be Object[]! @SuppressWarnings("unchecked") public Stack() { elements = (E[]) new Object[DEFAULT_INITIAL_CAPACITY]; } public void push(E e) { ensureCapacity(); elements[size++] = e; } public E pop() { if (size == 0) throw new EmptyStackException(); E result = elements[--size]; elements[size] = null; // Eliminate obsolete reference return result; } // no changes in isEmpty or ensureCapacity }
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 <T> UnaryOperator<T> identityFunction() { return (t) -> t; }
private static UnaryOperator<Object> IDENTITY_FN = (t) -> t; @SuppressWarnings("unchecked") public static <T> UnaryOperator<T> identityFunction() { return (UnaryOperator<T>) IDENTITY_FN; }
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; }
注:当列表是空的时候,这个方法会抛出IllegalArgumentException异常。一种更好的办法是返回一个Optional<E>。api
public class Stack<E> { public Stack(); public void push(E e); public E pop(); public boolean isEmpty(); // 生产者 public void pushAll(Iterable<? extends E> src) { for (E e : src) push(e); } // 消费者 public void popAll(Collection<? super E> dst) { while (!isEmpty()) dst.add(pop()); } } // 使用pushAll Stack<Number> numberStack = new Stack<>(); Iterable<Integer> integers = ... ; numberStack.pushAll(integers); // 使用popAll Stack<Number> numberStack = new Stack<Number>(); Collection<Object> objects = ... ; numberStack.popAll(objects);
// 修改前 public static <E> Set<E> union(Set<E> s1, Set<E> s2); // 修改后 public static <E> Set<E> union(Set<? extends E> s1, Set<? extends E> s2); // 使用 Set<Integer> integers = Set.of(1, 3, 5); Set<Double> doubles = Set.of(2.0, 4.0, 6.0); Set<Number> numbers = union(integers, doubles);
具体参考:泛型总结数组
// 修改前 public static <T extends Comparable<T>> T max(List<T> list); // 修改后 public static <T extends Comparable<? super T>> T max(List<? extends T> list); // 使用 // ScheduledFuture不直接实现Comparable,可是它的父类接口实现了Comparable,因此为了支持这种状况须要修改成<T extends Comparable<? super T>>。 List<ScheduledFuture<?>> scheduledFutures = ... ; max(scheduledFutures);
// 无界类型参数 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))); }
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> void putFavorite(Class<T> type, T instance) { favorites.put(type, type.cast(instance)); } public <T> T getFavorite(Class<T> type) { return type.cast(favorites.get(type)); } } // 使用 public static void main(String[] args) { Favorites f = new Favorites(); f.putFavorite(String.class, "Java"); f.putFavorite(Integer.class, 0xcafebabe); f.putFavorite(Class.class, Favorites.class); String favoriteString = f.getFavorite(String.class); int favoriteInteger = f.getFavorite(Integer.class); Class<?> favoriteClass = f.getFavorite(Class.class); System.out.printf("%s %x %s%n", favoriteString, favoriteInteger, favoriteClass.getName()); }
// 表示类,方法,属性和其余程序元素的反射类型实现 public interface AnnotatedElement { <T extends Annotation> T getAnnotation(Class<T> annotationType); } // 若是一个Class<?>的对象但愿传递给接收Class<T>的泛型方法,能够将对象转换为Class<? extends Annotation>,可是会有编译时警告,因此须要借助asSubclass转换所调用的Class对象来表示由其参数表示的类的子类。 static Annotation getAnnotation(AnnotatedElement element,String annotationTypeName) { Class<?> annotationType = null; // Unbounded type token try { annotationType = Class.forName(annotationTypeName); } catch (Exception ex) { throw new IllegalArgumentException(ex); } return element.getAnnotation(annotationType.asSubclass(Annotation.class)); }