泛型学习

泛型学习

因为公司的程序要兼容到JDK1.3,所以对泛型没有系统的去了解下。以下是在核心技术那本书上的摘抄:
使用泛型机制编写的程序代码要比那些杂乱地使用Object变量,然后再进行强制类型转换的代码具有更好的安全性和可读性。如:

ArrayList < Sting >  files  =   new  ArrayList < String > ();

一看就知道这个数组列表中包含的是String对象。同时编译器据此不需要强制类型转换,返回类型为String,而不是Object:

String file  =  files.get( 0 );

同时当files调用add方法,编译器知道有一个类型是String的参数。这会比使用Object参数更安全,编译器可以进行检查,避免错误类型的对象。
泛型类:具有一个或多个类型变量的类。如下面Pair类的代码:

public   class  Pair < T > {
  
private T first;
  
private T second;
  
public Pair(){
   
this.first = null;
   
this.second = null;
  }

  
public Pair(T first, T second){
   
this.first = first;
   
this.second = second;
  }

  
public T getFirst() {
   
return first;
  }

  
public void setFirst(T first) {
   
this.first = first;
  }

  
public T getSecond() {
   
return second;
  }

  
public void setSecond(T second) {
   
this.second = second;
  }

}

当构造函数两个域不同类型:

Public  class  Pair < T,U > {……}

补充:类型变量使用大写形式,且较短,如使用E表示集合的元素类型,K和V表示表的关键字与值的类型,T表示任意类型。
泛型方法:定义一个带有类型参数的简单方法。

class  GenericTest {
 
public static<T> T getMiddle(T[] a){
  
return a[a.length/2];
 }

}

泛型方法可以在普通的类中,也可以在泛型类中。当调用一个泛型方法时,
方法名前的尖括号中放入具体的类型:

String[] names  =   {"a","b","c"} ;
String  middle 
=  GenericTest. < String > getMiddle(names);

但是在大多数情况下,方法调用中可以省略<String>类型参数。
类型变量的限定:
如下代码,我们要计算数组中最小元素:

    static   class  GenericTest {
  
public static<T> T getMin(T[] a){
   
if(a == null || a.length  == 0){
    
return null;
   }

   T smallest 
= a[0];
   
for(int i=1; i<a.length;i++){
    
if(smallest.compareTo(a[i]) >0 )
     smallest 
= a[i];
   }

   
return smallest;
  }

 }

如此如何知道T所属的类有compareTo方法呢?,可以将T限制为实现Comparable接口的类,如:

public   static < extends  Comparable >  T getMin(T[] a) {。。。}

应此没有实现Comparable接口,调用getMin将会产生一个编译错误。
一个类型变量或通配符可以有多个限定,如:

< extends  Comparable  &  Serializable >

泛型代码和虚拟机
1. 虚拟机中没有泛型,只有普通的类和方法;
2. 所有的类型参数都用他们的边界替换;
3. 桥方法被合成为保持多态的;
4. 为保持类型的安全性,必要时插入强制类型转换。

约束与局限性
1、 基本类型:不能用类型参数替换基本类型。因此没有Pair<double>,只有Pair<Double>,原因是类型擦除之后Pair类具有Object类型的域,而Object不能存储double值。
2、 运行时类型查询:虚拟机中的对象总有一个特定的非泛型类型,所以所有的类型查询只产生原始类型。所以无论何时使用instanceof或设计类型的强制类型转换表达式都会看到一个编译警告。同样getClass方法总是返回原始类型。
3、 异常:不能抛出也不能捕获泛型类的对象泛型无法扩展Throwable都不合法。如:

public   class  Problem < T >   extends  Exception {…..} // 错误,

不能在catch子句中使用类型变量。但是在异常声明中可以使用类型变量。如:

       public < extends  Throwable >   void  test(Class < T >  a) {
           
try{  
           }
catch(Throwable e){  
          }

      }
// 可以通过

4、 数组:不能声明参数化类型的数组
5、 泛型类型的实例化:不能实例化泛型,如下面就是错误的:

public   class  Pair < T > {
 
public Pair(){
  
this.first = new T();
  
this.second = new T();
  }

}

6、不能在静态域或方法中引用类型变量。如下面的高招将无法实施:

public   class  Singleton < T > {
          
private static T singleInstance;//错误
          public static T getSingleInstance(){//错误
      if(singleInstance != null)
    
return singleInstance;
          }

 }

7、擦除后的冲突:要支持擦除的转换,需要强行限制一个类或类型变量不能同时成为两个接口类型的子类,而这个接口是同一接口的不同参数化。

 

你可能感兴趣的:(泛型学习)