Eclipse3.1中體驗J2SE5.0之泛型

  


J2SE 5.0中的最顯著的變化之一是添加對泛型類型的支持. 在J2SE 1.4 以及之前的版本中, Java程序並不是類型安全的. 例如, Collection Framework中定義的List, Map等容器類的元素都是Object類型, 即這個類包含的元素是Object對象. 使用這種方式實現的列表, 可以用來操作整數, 實數, 字符串或者任何對象類型. 例如  

 


List stringList = new ArrayList();
stringList.add("abcde");
String str = (String)stringList.get(0);
 

  這種方法實現的列表需要使用強制類型轉換(又稱顯示造型), 因此不是類型安全的. 在上面這段代碼種, 雖然變量名爲stringList, 但是我們仍然可以把一個整型對象添加到這個隊列中, 例如,

  


stringList.add(new Integer(5));
 

  在這種情況下, 從字符列表中獲取對象時, 強制類型轉換就會導致運行時異常.

  


String str = (String)stringList.get(1); //runtime exception
 

  泛型是java邁向類型安全的一個重要步驟, 使用泛型可以構造出類型安全的代碼.

  

  所謂泛型是指類型參數化(parameterized types). java是一種強類型的語言, 在J2SE 1.4以及以前的版本中, 我們在定義一個java類, 接口或者方法的時候, 必須指定變量的類型. 在聲明泛型類、接口或者函數時, 定義變量的時候不指定某些變量的具體類型, 而是用一個類型參數代替. 在使用這個類, 接口, 或者方法的時候, 這個類型參數由一個具體類型所代替.

  2.1 泛型類

  下面的例子中介紹瞭如何創建一個最簡單泛型類

  


public class GenSample<T> {}
 

  類名後面帶有<T>表明了這個類是泛型類, 其中T被成爲類型參數(type parameter), 在使用泛型的時候, 類型參數可以被替換爲任何的類類型, 但是不能是原始類型(primitive type), 例如int, double.

  下面通過一個列表的例子來具體說明如果聲明泛型類和類型參數的用法.

  


public class GenList <T>{
 private T[] elements;
 private int size = 0;
 private int length = 0;

 public GenList(int size) {
  elements = (T[])new Object[size];
  this.size = size;
 }

 public T get(int i) {
  if (i < length) {
   return elements[i];
  }
  return null;
 }
 
 public void add(T e) {
  if (length < size - 1)
   elements[length++] = e;
 }
}
 

  在列表的例子中, 類型參數T被用來表示列表中的元素的類型, 即, 這個列表中的元素是T類型的.

  在使用這個列表時, 這個類型參數T會被具體的類型所替代.

  注意, 由於T時類型參數不是具體的類, 所以不能使用new操作符創建T的對象,例如new T(), 或者, new T[10].

  2.2 泛型接口

  在J2SE 5.0中, 不僅僅可以聲明泛型類, 也可以聲明泛型接口, 聲明泛型接口和聲明泛型類的語法類似, 也是在接口命稱後面加上<T>. 例如,

  

public interface GenInterface<T> {
    void func(T t);
}
 

  2.3、聲明多個類型參數的泛型類或者接口

  在聲明泛型類的時候, 可是使用多個類型參數. 多個類型參數之間用逗號分開, 例如,

  

public class GenMap<T, V> {}
 

  Eclipse 3.1的類創建嚮導支持創建泛型類, 如下圖所示,

  

 

  使用Eclipse接口嚮導創建泛型接口

  


XMLns:xsi="http://www.w3.org/2001/XMLSchema-instance">  2.4 泛型方法

  類型參數(type parameter)不僅僅可以用來聲明泛型類或者泛型接口, 也可以用來聲明泛型方法, 而且這種聲明的泛型方法可以用在非泛型類中, 聲明泛型方法的一般格式是

  

<type-list> return-type method-name(parameter-list) {}
 

  

public <T> String getString(T obj) {
 return obj.toString();
}
 

  2.5 受限泛型

  受限泛型是指類型參數的取值範圍是受到限制的. extends關鍵字不僅僅可以用來聲明類的繼承關係, 也可以用來聲明類型參數(type parameter)的受限關係.例如, 我們只需要一個存放數字的列表, 包括整數(Long, Integer, Short), 實數(Double, Float), 不能用來存放其他類型, 例如字符串(String), 也就是說, 要把類型參數T的取值泛型限制在Number極其子類中.在這種情況下, 我們就可以使用extends關鍵字把類型參數(type parameter)限制爲數字,

  
public class Limited<T extends Number> {
 public static void main(String[] args) {
  Limited<Integer> number;   //正確
  Limited<String> str;       //編譯錯誤
 }
}
 

  在Eclipse 3.1中, 上例中的編譯錯誤信息如下圖所示

  

 

  

  3.1在程序中使用泛型類

  在創建泛型類的對象的時候, 和創建普通對象基本類似, 必須提供具體的類類型來替代類型參數T (J2SE 5.0目前不支持原始類型作爲類型參數(type parameter)).

  

//如果需要整型的列表
GenList<Integer> integerList = new GenList<Integer>();
//如果需要字符型的列表
GenList<String> strList = new GenList<String>();
//不能使用原始類型
GenList<int> nList = new GenList<int>();  //編譯錯誤
 

  

  使用泛型實現的列表是類型安全的, 下列破壞類型安全語句會在編譯的時候檢查出來。 把鼠標放在錯誤標記上, Eclipse 3.1中的錯誤提示就會顯示,如下圖所示:

  


  3.3 二義性錯誤

  GenMap在聲明是使用了2個類型參數T和V, 因此在創建GenMap的對象的時候也需要提供2個具體的類類型來替代這2個類型參數, 例如,

  

GenMap<Integer, String> gm = new GenMap<Integer, String>();
GenMap<String, String> gm2 = new GenMap<String, String>();
 

  上例中, T和V雖然看起來是兩個不同的類型參數, 但是在使用這個泛型類的時候, T和V很有可能被替換成同一種類型. 因此在聲明多個類型參數的泛型類時, 要注意避免這種二義性錯誤, 例如,

  

public class GenMap<T, V> {
    //編譯錯誤, 二義性錯誤
    public void set(T t){}
    public void set(V v){}
}
 

  在上面這段代碼, 如果T和V被替換成同一種類型, set函數的簽名(signature)就是完全一樣的, 所以編譯器會報告二義性錯誤. 正確的用法是聲明2個不同名的方法, 例如,

  

public class GenMap<T, V> {
    public void setKey(T t){}
    public void setValue(V v){}
}
 

  


  3.4 使用通配符

  前面我們創建了泛型的列表, 如果我需要一個方法來處理泛型列表, 例如, 我們希望把列表中的每個元素都打印出來, 但是類型參數(type parameter)只能使用在聲明一個泛型類的時候, 如果類型參數使用在函數定義裏會導致編譯錯誤。


public static void print(GenList<T> list){} //編譯錯誤
 


  在這種情況下, 我們需要用另外一種方法來表示一個泛型類, 否則, 就可能需要書寫多個print函數。


public static void print(GenList<Integer> list){}
public static void print(GenList<Double> list){}

public static void print(GenList<String> list){}
 


  J2SE 5.0中提供了泛型的通配符"?", "?"可以用來代替任何類型, 例如使用通配符來實現print方法。


public static void print(GenList<?> list) {}
 


  

  (1) 類型參數不能實例化, 例如,


T t= new T();   //編譯錯誤
 

  (2) 不能實例化類型參數的數組


T[] ts= new T[10];   //編譯錯誤
 


  (3) 類的靜態變量不能聲明爲類型參數類型


public class GenClass<T> {
     private static T t;    //編譯錯誤
}
 


  (4) 泛型類不能繼承自Throwable以及其子類


public GenExpection<T> extends Exception{}    //編譯錯誤
 


  

  泛型是J2SE 5.0所提供的一項強大的功能, 使用泛型可以創建類型安全的、可重用的代碼, 雖然目前java的泛型還無法和C++的泛型相提並論, 但是, 隨着java語言本事的演進, 泛型會在java語言中發揮更大的作用的.

發佈了80 篇原創文章 · 獲贊 0 · 訪問量 10萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章