一、java 泛型引入
List list = new ArrayList(); list.add("abc"); list.add(new Integer(1)); //可以通过编译 for (Object object : list) { System.out.println((String)object);//抛出ClassCastException异常 }
List<String> list = new ArrayList<>(); list.add("abc"); //list.add(new Integer(1)); //编译错误 for (String string : list) { System.out.println(string);//无需任何强制类型转换 }
二、泛型的类与接口
public class Gen { private Object obj; public Object getObj() { return obj; } public void setObj(Object obj) { this.obj = obj; } public static void main(String[] args) { Gen gen = new Gen(); gen.setObj("abc"); String str = (String) gen.getObj();//类型转换,可能会引起运行时ClassCastException } }
public class Gen<T> { T obj; public T getObj() { return obj; } public void setObj(T obj) { this.obj = obj; } public static void main(String[] args) { Gen<String> gen = new Gen<>(); gen.setObj("abc"); // gen.setObj(10); //无法通过编译 String str = gen.getObj(); //无需类型转换 //----------------------------- Gen gen2 = new Gen();//raw type原始类型 gen2.setObj("abc"); gen2.setObj(10); //可以通过编译,自动装箱将10转化为Integer对象 Integer num = (Integer) gen2.getObj();//使用了强制类型转换 } }
public interface List <E> { void add(E x); Iterator<E> iterator(); } public interface Iterator<E> { E next(); boolean hasNext(); }
三、泛型的命名规范
- E — Element,常用在java Collection里,如:List<E>,Iterator<E>,Set<E>
- K,V — Key,Value,代表Map的键值对
- N — Number,数字
- T — Type,类型,如String,Integer等等
- S,U,V etc. - 2nd, 3rd, 4th 类型,和T的用法一样
四、泛型的方法与构造函数
public class GenMethod { public static <T> void fromArrayToCollection(T[] a,Collection<T> c){ for (T t : a) { c.add(t); } } public static void main(String[] args) { Object[] oa = new Object[100]; Collection<Object> co = new ArrayList<>(); GenMethod.<Object>fromArrayToCollection(oa, co); } }
public static <T> void fromArrayToCollection(T[] a,Collection<T> c){ for (T t : a) { c.add(t); c.add(new Object()); } }
String[] sa = new String[100]; Collection<String> cs = new ArrayList<String>(); // T 推断为String fromArrayToCollection(sa, cs); // T 推断为Object fromArrayToCollection(sa, co); Integer[] ia = new Integer[100]; Float[] fa = new Float[100]; Number[] na = new Number[100]; Collection<Number> cn = new ArrayList<Number>(); //T 推断为Number fromArrayToCollection(ia, cn); //T 推断为Number fromArrayToCollection(fa, cn); //T 推断为Number fromArrayToCollection(na, cn); //T 推断为Object fromArrayToCollection(na, co); //编译错误,Number与String不能兼容 fromArrayToCollection(na, cs);
五、泛型参数的界限
public class Box<T> { private T t; public void set(T t) { this.t = t; } public T get() { return t; } public <U extends Number> void inspect(U u) { System.out.println("T: " + t.getClass().getName()); System.out.println("U: " + u.getClass().getName()); } public static void main(String[] args) { Box<String> integerBox = new Box<>(); integerBox.set("abc"); //能通过编译,因为T指定为String类型 // integerBox.inspect("abc");//不能通过编译,因为U必须是Number类型或其子类 integerBox.inspect(new Integer(10)); } }
public class NumberTest<T extends Integer> { private T num; public NumberTest(T num) { this.num = num;} public boolean isOdd(){ return num.intValue()%2 == 1; } //.... }
Class A { /* ... */ } interface B { /* ... */ } interface C { /* ... */ } class D <T extends A & B & C> { /* ... */ }
class D <T extends B & A & C> { /* ... */ } // 无法通过编译
六、泛型方法与泛参界限的综合
泛型与Comparable、Comparator相结合,作为比较对象的补充。因为在基本比较操作符是无法直接应用于对象中的。
public static <T> int countGreater(T[] array,T elem) { int count = 0; for (T t : array) { if (t > elem) {//编译错误 ++count; } } return count; }
public interface Comparable<T> { public int compareTo(T o); }
public static <T extends Comparable<T>> int countGreater(T[] array,T elem) { int count = 0; for (T t : array) { if (t.compareTo(elem) > 0) {//无编译错误 ++count; } } return count; }
七、泛型、继承与子类型
可以将第七点与第八点进行联合对比,谨记基础类型的继承与泛型类型之间的子类型的区别与联系
String someString = new String(); Object someObject = new Object(); someObject = someString;
public void someMethod(Number n) { /* ... */ } someMethod(new Integer(10)); // OK someMethod(new Double(10.1); // OK
Box<Number> box = new Box<>(); box.add(new Integer(1)); box.add(new Double(1.0));
public void someMethod(Box<Number> n) { /*.....*/}
这个方法可以接受什么类型的参数呢??显然,这个方法接受Box<Number>类型的参数??那又是否可以接受Box<Integer>或者Box<Double>类型的参数的??答案是
否定的,因为Box<Integer>与Box<Double>都不是Box<Number>的子类。在泛型编程里,这是一个容易混淆的概念,但又必须要懂的原理。如下图:
从图可以看到,即使Integer是Number的子类,但Box<Integer>并不是Box<Number>的子类。Box<Integer>与Box<Number>的共同父类是Object。换言之,无论类A与类B是否存在关联,MyClass<A>与MyClass<B>都没有任何关联,其共同的父类的是Object。那是否说,泛型就不存在子类呢??这个留待解决,看完本文便可以知晓。
八、泛型类与子类型
interface PayloadList<E,P> extends List<E> { void setPayload(int index, P val); //... }