转自 http://peiquan.blog.51cto.com/7518552/1302898
一、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();//使用了强制类型转换
}
}
细心的你会发现在main()方法里是使用泛型类型Gen<String>,便不再需要强制类型转换,也就移除了运行时的ClassCastException。同时为了区别,在此也定义了一个没有使用泛型类型的gen2,这时,编译器会弹出一个警告“Gen is a raw type,References to generic type Gen<T> should be parameterized”。当我们不提供泛型类型时,会默认使用Object会代替,也是因此这样,gen2可以设置String和Integer类型,不过,我们应尽量去避免这种这种情况的出现,如此,便又需要用到强制类型转换,也伴随着运行时的ClassCastException异常。
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> { /* ... */ } // 无法通过编译
五、泛型方法与泛参界限的综合
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);
//...
}
PayloadList<String,String>
PayloadList<String,Integer>
PayloadList<String,Exception>
如图