@gnudennis
2015-05-09T14:51:38.000000Z
字数 4761
阅读 3994
CoreJava
- 高级语法:通配符
- 最佳实践
本文介绍泛型的高级语法已经最佳实践。Java 泛型的很多限制都可以从上篇中的原理(Java 泛型机制) 来解释。
通配符是使用的角度而言的,在编译器期间执行更加严格的检查。
语法:
Pair<? extends Employee>
继承关系:
限制:
只需要从编译器如何翻译代码块的角度思考这些限制。
Employee emp = new Employee();Manager ceo = new Manager();Manager cfo = new Manager();Pair<Manager> managerBuddies = new Pair<Manager>(ceo, cfo);Pair<? extends Employee> wildcardBuddies = managerBuddies; // OK// 编译器只知道是某个Employee的子类,编译器推断不出具体的类型// 限制: 编译器拒绝任何特定类型// void setFirst(? extends Employee)wildcardBuddies.setFirst(ceo); // compile-time errorwildcardBuddies.setFirst(emp); // compile-time errorwildcardBuddies.setFirst(new Object()); // compile-time error// ? extends Employee getFirst()Employee ret = wildcardBuddies.getFirst(); // OK
语法:
Pair<? super Manager>
继承关系:

限制:
Employee e1 = new Employee();Employee e2 = new Employee();Manager ceo = new Manager();Pair<Employee> employeeBuddies = new Pair<Employee>();Pair<? super Manager> wildcardBuddies = employeeBuddies; // OK// 编译器值知道是某个Manager的父类// 限制: 编译器拒绝任何特定类型// ? super ManagerManager ret = wildcardBuddies.getFirst(); // compile-time error// void setFirst(? super Manager)wildcardBuddies.setFirst(e1); // compile-time errorwildcardBuddies.setFirst(ceo); // OK
更加严格的写法:
public static <T extends Comparable> T min(T[] a);// 更加严格的写法public static <T extends Comparable<? super T>> T min(T[] a);
解释:
该泛型方法使用Comparable<? super T>进行擦除,现在 compareTo 写成:
int compareTo(? super T). 表明只需要 T的父类有 compareTo() 方法即可.
例如:GregorianCalendar 是 Calendar 的子类,Calendar实现了Comparable, 但是 GregorianCalendar 并没有重写Comparable, 所以:
public static > T min(T[] a); 是不够的。
语法:
Pair
限制:
? getFirst(); // 只能赋给一个Objectvoid setFirst(?); // 无法调用, Object也不行
存在的理由:
对于简单的操作,代替泛型方法,更加具有可读性。
比如:
public static <T> boolean hasNulls(Pair<T> p)// 可以写成:public static boolean hasNull(Pair<?> p) {return p.getFirst() == null || p.getSecond() == null;}
局限:
? 不能作为一种类型。? t = xx 非法。
这样导致只能代替操作简单的泛型方法。比如swap都写不了.
public static void swap(Pair<?> p) {? t = p.getFirst; // ERRORp.setFirst(p.getSecond);p.setSecond(t);}// 这时候只能:public static <T> void swapHelper(Pair<T> p) {T t = p.getFirst; // ERRORp.setFirst(p.getSecond);p.setSecond(t);}public static void swap(Pair<?> p) {swapHelper(p);}
if (a instanceof Pair<String>) // same as "a instanceof Pair"if (a instanceof Pair<T>) // T is ignoredPair<String> p = (Pair<String>)a; // can only test that a is a PairPair<String> stringPair = ...;Pair<Employee> employeePair = ...;if (stringPair.getClass() == employeePair.getClass()) // they are equal, Pair.class
// 1. 泛型类无法扩展 Throwablepublic class Problem<T> extends Exception {/*...*/} // ERROR -- can't extend Throwable(编译无法通过)// 2. 不能抛出泛型类示例public static <T extends Throwable> void doWork(Class<T> t) {try {do work} catch (T e) {// ERROR -- cant't catch type variableLogger.global.info(...)}}// 正确时间:public static <T extends Throwable> void doWork(Class<T> t) {try {do work} catch (Throwable realCause) {t.intCause(realCause);throw t;}}
Pair<String>[] table = new Pair<String>[10]; // ERROR
new T(...), new T[...], T.class 非法. 但是可以声明.
问题1.
public Pair() { first = new T(); second = new T(); } // ERRORfirst = T.class.newInstance(); // ERROR// 最佳实践: 指定T的类型public static <T> Pair<T> makePair(Class<T> clazz) {try {return new Pair(clazz.newInstance(), clazz.newInstance());} catch (Exception e) {return null;}}Pair<String> stringPair = Pair.<String>makePair(String.class);// OK
问题2.
public static <T extends Comparable<? super T>> T[] minmax(T... a) {// T[] mm = new T[2]; // ERROR, Type parameter 'T' cannot be instantiated directlyObject[] mm = new Object[2];mm[0] = a[0];mm[1] = a[1];return (T[])mm; // T 被擦成Comparable, 运行时会ClassCastException, 而Object不是Comparable}public static void main(String[] args) {String[] ss = minmax("Tom", "Dick", "Harry"); // ClassCastException!!!}// Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.Comparable}// 最佳实践:public static <T extends Comparable<? super T>> T[] minmax(T... a) {T[] mm = (T[])Array.newInstance(a.getClass().getComponentType(), 2);...return mm;}
问题3.
public class ArrayList<T> {private T[] elements;public ArrayList() { elements = (T[]) new Object[10]; }public T get(int n) { return elements[n]; }public void set(int n, T e) { elements[n] = e; }public static void main(String[] args) {ArrayList<String> src = new ArrayList<String>();src.set(0, "hello");src.set(1, "world");// String[]和Object[]是不同的类型.// String[] copy = src.toArray(); // Exception in thread "main" java.lang.ClassCastException: [Ljava.lang.Object; cannot be cast to [Ljava.lang.String;String[] copy2 = new String[100];src.toArray(copy2);System.out.println(Arrays.toString(copy2)); // OK}public T[] toArray() {// 可以分析:elements.getClass().getComponentType()实质是Object, 所以返回的类型实质是:Object[],T[] result = (T[]) Array.newInstance(elements.getClass().getComponentType(), elements.length);return result;}public T[] toArray(T[] src) {for (int i = 0; i < elements.length; ++i) {src[i] = elements[i];}return src;}}
Pair<T> 和 Pair<S> 没有继承关系.Java SE5.0 增加了 java.lang.reflect.Type 来支持类型的反射信息.
public void > minmax(T... a);
