程序師世界是廣大編程愛好者互助、分享、學習的平台,程序師世界有你更精彩!
首頁
編程語言
C語言|JAVA編程
Python編程
網頁編程
ASP編程|PHP編程
JSP編程
數據庫知識
MYSQL數據庫|SqlServer數據庫
Oracle數據庫|DB2數據庫
 程式師世界 >> 編程語言 >> JAVA編程 >> 關於JAVA >> 在Eclipse 3.1中體驗J2SE 5.0的新特性: 第三部分 :范型

在Eclipse 3.1中體驗J2SE 5.0的新特性: 第三部分 :范型

編輯:關於JAVA

J2SE 5.0 (Tiger)的發布是Java語言發展史上的一個重要的裡程碑, 是迄今為止在 Java 編程方面所取得的最大進步。

J2SE 5.0提供了很多令人激動的特性。這些特性包括范型(generics)的支持, 枚舉類 型(enumeration)的支持, 元數據(metadata)的支持, 自動拆箱(unboxing)/裝箱 (autoboxing), 可變個數參數(varargs), 靜態導入(static imports), 以及新的線程架 構(Thread framework)。

隨著J2SE 5.0的推出, 越來越多的集成開發環境(IDE)支持J2SE 5.0的開發。著名的開源Java IDE Eclipse從3.1M4開始支持J2SE 5.0的開發, 目前最新的版本是3.1RC4。

本系列將介紹J2SE 5.0中三個比較重要的特性: 枚舉類型, 注釋類型, 范型, 並在此 基礎上介紹在如何在Eclipse 3.1開發環境中開發枚舉類型, 注釋類型和范型應用。本文 將介紹范型。

3. 范型

3.1范型(Generics)簡介

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

清單3.1.1 類型不安全的代碼示例

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

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

清單3.1.2 類型不安全的代碼示例

stringList.add(new Integer(5));

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

清單3.1.3 類型不安全的代碼示例

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

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

3.2聲明范型

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

3.2.1 范型類

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

清單3.2.1, 最簡單的范型類

public class GenSample<T> {}

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

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

清單3.2.2, 范型列表

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].

3.2.2 范型接口

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

清單3.2.3, 范型接口

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

3.2.3聲明多個類型參數的范型類或者接口

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

清單3.2.4, 多個類型參數的范型類

public class GenMap<T, V> {}

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

圖3.2.1 使用類向導創建范型類

使用Eclipse接口向導創建范型接口

圖3.2.2 使用接口向導創建范型接口

3.2.4范型方法

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

清單3.2.5 范型方法的一般形式

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

清單3.2.6 范型方法示例

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

3.2.5 受限范型

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

清單3.2.7 受限范型示例

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

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

圖3.2.3 由於受限范型導致的編譯錯誤

3.3 在程序中使用范型

3.3.1在程序中使用范型類

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

清單3.3.1, 使用范型類

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

3.3.2 使用范型解決類型安全性問題

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

圖3.3.2 破壞類型安全引起的錯誤

3.3.3 二義性錯誤

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

清單9, 多個參數的范型類

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

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

清單10, 二義性錯誤

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

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

清單10, 二義性錯誤

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

圖3.3.3 二義性錯誤

3.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) {}

3.4. 范型的一些局限型

(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{}  //編譯錯誤

3.5.范型小結

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

  1. 上一頁:
  2. 下一頁:
Copyright © 程式師世界 All Rights Reserved