【java基礎(五十)】爲什麼要使用泛型程序設計

從Java程序設計語言1.0版發佈以來,變化最大的部分就是泛型。致使Java SE 5.0中增加泛型機制的主要原因是爲了滿足1999年制定的最早的Java規範需求之一(JSR 14)。專家組花費了5年左右的時間用來定義規範和測試實現。

泛型正是我們需要的程序設計手段。使用泛型機制編寫的程序代碼要比那些雜亂地使用Object變量,然後再進行強制類型轉換的代碼具有更好的安全性和可讀性。泛型對於集合類尤其有用。

爲什麼要使用泛型程序設計

泛型程序設計(Generic programming)意味着編寫的代碼可以被很多不同類型的對象所重用。例如,我們並不希望爲聚集String和File對象分別設計不同的類。實際上,也不需要這樣做。因爲一個ArrayList類可以聚集任何類型的對象。這是一個泛型程序設計的實例。

實際上,在Java增加泛型類之前已經有一個ArrayList類。下面來研究泛型設計的機制是如何演變的,另外還會講解這對於用戶和實現着來說意味着什麼。

類型參數的好壞

在Java中增加泛型類之前,泛型程序設計是用繼承實現的。ArrayList類只維護一個Object引用的數組:

public class ArrayList {
	private Object[] elementData;
	...
	public Object get(int i) {...}
	public void add(Object o) {...}
}

這種方法有兩個問題。當獲取一個值時必須進行強制類型轉換。

ArrayList files = new ArrayList();
...
String filename = (String)file.get(0);

此外,這裏如果沒有錯誤檢查。可以向數組列表中添加任何類的對象。

files.add(new File("..."));

對於這個調用,編譯和運行都不會出錯。然而在其他地方,如果將get的結果強制類型轉換爲String類型,就會產生一個錯誤。

泛型提供了一個更好的解決方案:類型參數(type parameters)。ArrayList類有一個類型參數來指示元素的類型:

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

編譯器也可以很好的利用這個信息。當調用get的時候,不需要進行強制類型轉換,編譯器就知道返回值類型爲String,而不是Object:

String filename = files.get(0);

編譯器還知道ArrayList<String>中add方法有一個類型爲String的參數。這將比使用Object類型的參數安全一些。現在,編譯器可以進行檢查,避免插入錯誤類型的對象。如:

files.add(new File("..."));	// 這裏將無法通過編譯

是無法通過編譯的。出現編譯錯誤比類在運行時出現類的強制類型轉換異常要好得多。

類型參數的魅力在於:使得程序具有更好的可讀性和安全性。

泛型程序設計的能力級別

使用想ArrayList的泛型類很容易。大多數Java程序員都使用ArrayList<String>這樣的類型,就好像他們已經構建在語言之中,像String[]數組一樣。

但是,實現一個泛型並沒還有那麼容易。對於類型參數,使用這段代碼的程序員可能想要內置(plug in)所有的類。他們希望在沒有過多的限制以及混亂的錯誤消息的狀態下,做所有的事情。因此,一個泛型程序員的任務就是預測出所有類的未來可能有的所有用途。

這一任務難到什麼程度呢?下面是標準類庫的設計者們肯定產生爭議的一個典型問題。ArrayList類有一個方法addAll用來添加另一個集合的全部元素。程序員可能想要將ArrayList<Manage>中的所有元素添加到ArrayList<Employee>中去。然而,反過來就不行了。如何只能允許前一個調用,而不能允許後一個調用呢?Java語言的設計者發明了一個具有獨特性的性概念,通配符類型(wildcart type),它解決了這個問題。通配符類型非常抽象,然而,他們能讓庫的構建者編寫出儘可能靈活的方法。

泛型程序設計劃分爲3個能力級別。基本級別是,僅僅使用泛型類,典型的是想ArrayList這樣的集合,不必考慮他們的工作方式與原因。大多數應用程序猿將會停留在這一級別上,知道出現了什麼問題。當把不同的泛型類混合在一起時,或是在於對類型參數一無所知的遺留的代碼進行銜接時,可能會看到含糊不清的錯誤消息。如果這樣的話,就需要學習Java泛型來系統地解決這些問題,而不要胡亂地猜測。當然,最終可能想要實現自己的泛型類與泛型方法。

應用程序猿很可能不喜歡編寫太多的泛型代碼。JDK開發人員已經做出了很大的努力,爲所有的集合類提供了類型參數。憑經驗來說,那些原本涉及許多來自通用類型(如Object或Comparable接口)的強制類型轉換的代碼一定會因使用類型參數而受益。

捐贈

若你感覺讀到這篇文章對你有啓發,能引起你的思考。請不要吝嗇你的錢包,你的任何打賞或者捐贈都是對我莫大的鼓勵。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章