Java基础篇之泛型详解下篇

5.通配符
为了引出通配符的概念,先看如下代码:

List ex_int= new ArrayList();    
List ex_num = ex_int; //非法的  

上述第2行会出现编译错误,因为Integer虽然是Number的子类,但List不是List的子类型。

假定第2行代码没有问题,那么我们可以使用语句ex_num.add(newDouble())在一个List中装入了各种不同类型的子类,这显然是不可以的,因为我们在取出List中的对象时,就分不清楚到底该转型为Integer还是Double了。

因此,我们需要一个在逻辑上可以用来同时表示为ListList的父类的一个引用类型,类型通配符应运而生。在本例中表示为List即可。下面这个例子也说明了这一点,注释已经写的很清楚了。

public static void main(String[] args) {  
   FX ex_num = new FX(100);  
   FX ex_int = new FX(200);  
   getData(ex_num);  
   getData(ex_int);//编译错误  
}  
 
public static void getData(FX temp) { //此行若把Number换为“?”编译通过  
   //do something...  
}  
     
public static class FX {  
   private T ob;   
   public FX(T ob) {  
       this.ob = ob;  
   }  
}  

6.上下边界
看了下面这个上边界的例子就明白了,下界FX的形式就不做过多赘述了。

public static void main(String[] args) {  
    FX ex_num = new FX(100);  
    FX ex_int = new FX(200);  
    getUpperNumberData(ex_num);  
    getUpperNumberData(ex_int);  
}  
  
public static void getUpperNumberData(FX temp){  
      System.out.println("class type :" + temp.getClass());  
}  
      
public static class FX {  
    private T ob;   
    public FX(T ob) {  
    this.ob = ob;  
    }  
}  

7.泛型的好处
**(1)类型安全 **
通过知道使用泛型定义的变量的类型限制,编译器可以更有效地提高Java程序的类型安全。
(2)消除强制类型转换
消除源代码中的许多强制类型转换。这使得代码更加可读,并且减少了出错机会。所有的强制转换都是自动和隐式的。
(3)提高性能

Lits list1 = new ArrayList();  
list1.add("CSDN_SEU_Cavin ");  
String str1 = (String)list1.get(0);  

List list2 = new ArrayList();  
list2.add("CSDN_SEU_Cavin ");  
String str2 = list2.get(0);  

对于上面的两段程序,由于泛型所有工作都在编译器中完成,javac编译出来的字节码是一样的(只是更能确保类型安全),那么何谈性能提升呢?是因为在泛型的实现中,编译器将强制类型转换插入生成的字节码中,但是更多类型信息可用于编译器这一事实,为未来版本的 JVM 的优化带来了可能。

8.泛型使用的注意事项

(1)泛型的类型参数只能是类类型(包括自定义类),不能是简单类型。
(2)泛型的类型参数可以有多个。
(3)不能对确切的泛型类型使用instanceof操作。如下面的操作是非法的,编译时会出错。

if(ex_num instanceof FX){   
}  

(4)不能创建一个确切的泛型类型的数组。下面使用Sun的一篇文档的一个例子来说明这个问题:

List[] lsa = new List[10]; // Not really allowed.    
Object o = lsa;    
Object[] oa = (Object[]) o;    
List li = new ArrayList();    
li.add(new Integer(3));    
oa[1] = li; // Unsound, but passes run time store check    
String s = lsa[1].get(0); // Run-time error: ClassCastException.    

这种情况下,由于JVM泛型的擦除机制,在运行时JVM是不知道泛型信息的,所以可以给 oa[1]赋上一个ArrayList而不会出现异常,但是在取出数据的时候却要做一次类型转换,所以就会出现ClassCastException,如果可以进行泛型数组的声明,上面说的这种情况在编译期将不会出现任何的警告和错误,只有在运行时才会出错。
下面采用通配符的方式是被允许的:

List[] lsa = new List[10]; // OK, array of unbounded wildcard type.    
Object o = lsa;    
Object[] oa = (Object[]) o;    
List li = new ArrayList();    
li.add(new Integer(3));    
oa[1] = li; // Correct.    
Integer i = (Integer) lsa[1].get(0); // OK 

你可能感兴趣的:(Java基础篇之泛型详解下篇)