Core Java笔记 8.泛型(II) - 高级语法与最佳实践
2015-05-09 22:52
344 查看
本章重点:
高级语法:通配符
最佳实践
本文介绍泛型的高级语法已经最佳实践。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 error wildcardBuddies.setFirst(emp); // compile-time error wildcardBuddies.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 Manager Manager ret = wildcardBuddies.getFirst(); // compile-time error // void setFirst(? super Manager) wildcardBuddies.setFirst(e1); // compile-time error wildcardBuddies.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 extends Comparable> T min(T[] a); 是不够的。
补充:无限定通配符
语法:Pair<?>
限制:
? getFirst(); // 只能赋给一个Object void 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; // ERROR p.setFirst(p.getSecond); p.setSecond(t); } // 这时候只能: public static <T> void swapHelper(Pair<T> p) { T t = p.getFirst; // ERROR p.setFirst(p.getSecond); p.setSecond(t); } public static void swap(Pair<?> p) { swapHelper(p); }
最佳实践
1.不能使用基本类型实例化类型参数. 才有 wrapper 即可.
2.类型查询只适用于原始类型. 即类型检查直接使用原始类型即可.
if (a instanceof Pair<String>) // same as "a instanceof Pair" if (a instanceof Pair<T>) // T is ignored Pair<String> p = (Pair<String>)a; // can only test that a is a Pair Pair<String> stringPair = ...; Pair<Employee> employeePair = ...; if (stringPair.getClass() == employeePair.getClass()) // they are equal, Pair.class
3.泛型类无法扩展 Throwable,也无法抛出泛型类.
// 1. 泛型类无法扩展 Throwable public 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 variable Logger.global.info(...) } } // 正确时间: public static <T extends Throwable> void doWork(Class<T> t) { try { do work } catch (Throwable realCause) { t.intCause(realCause); throw t; } }
4.参数化类型的数组不合法,而是采用容器类存储.
Pair<String>[] table = new Pair<String>[10]; // ERROR
5.可以声明类型参数,但不能实例化类型参数
new T(...), new T[...], T.class 非法. 但是可以声明.问题1.
public Pair() { first = new T(); second = new T(); } // ERROR first = 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 directly Object[] 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 ; } public void set(int n, T e) { elements = 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; } }
6.不能在静态域或者方法中使用类型变量. 因为静态域是类共享的.
7. 当T和S有继承关系时,Pair<T>
和 Pair<S>
没有继承关系.
8. Java SE5.0 增加了对泛型的反射API.
Java SE5.0 增加了 java.lang.reflect.Type 来支持类型的反射信息.public void <T extends Comparalbe<? super T>> minmax(T... a);
相关文章推荐
- [原创]Java最佳实践笔记。(不断更新)
- [转]CoreJava学习笔记_Java语法基础
- Java对泛型的支持(二)- 高级语法
- Java对泛型的支持(二)- 高级语法
- Core Java笔记 7.泛型(I) - 概念,语法与原理
- 24. javacript高级程序设计-最佳实践
- Android(java)学习笔记92:泛型高级之通配符
- Java 回顾笔记_集合框架-泛型高级应用
- [core Java学习笔记][第一二三章基本语法]
- [core Java学习笔记][第一二三章基本语法]
- Java内存回收知识(读书笔记)--深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)2.2~2.3
- Java内存回收知识(读书笔记)--深入理解Java虚拟机——JVM高级特性与最佳实践(第2版)--2.2
- [连载] 深入理解Java虚拟机(JVM高级特性与最佳实践) 学习笔记连载分享
- [连载] 深入理解Java虚拟机(JVM高级特性与最佳实践)之 【走近Java】
- Java高级语法笔记-抽象类
- Java高级语法笔记-库的使用(jar)
- Java高级语法笔记-普通异常处理
- Java高级语法笔记-多个异常处理
- Java高级语法笔记-自定义异常类
- Java高级语法笔记-向上层抛出异常