what are you 弄啥嘞!!!!!!!!!!!!!!!!泛型
1.為什麽需要泛型
泛型在Java中有很重要的地位,網上很多文章羅列各種理論,不便於理解,本篇將立足於代碼介紹、總結了關於泛型的知識。希望能給你帶來一些幫助。
先看下面的代碼:
- List list = new ArrayList();
- list.add("CSDN_SEU_Cavin");
- list.add(100);
- for (int i = 0; i < list.size(); i++) {
- String name = (String) list.get(i); //取出Integer時,運行時出現異常
- System.out.println("name:" + name);
- }
本例向list類型集合中加入了一個字符串類型的值和一個Integer類型的值。(這樣合法,因為此時list默認的類型為Object類型)。在之後的循環中,由於忘記了之前在list中也加入了Integer類型的值或其他原因,運行時會出現java.lang.ClassCastException異常。為了解決這個問題,泛型應運而生。
2.泛型的使用
Java泛型編程是JDK1.5版本後引入的。泛型讓編程人員能夠使用類型抽象,通常用於集合裏面。
只要在上例中將第1行代碼改成如下形式,那麽就會在編譯list.add(100)時報錯。
- List<String> list = new ArrayList<String>();
通過List<String>,直接限定了list集合中只能含有String類型的元素,從而在上例中的第6行中,無須進行強制類型轉換,因為集合能夠記住其中元素的類型信息,編譯器已經能夠確認它是String類型了。
3.泛型只在編譯階段有效
看下面的代碼:
- AyyayList<String> a = new ArrayList<String>();
- ArrayList b = new ArrayList();
- Class c1 = a.getClass();
- Class c2 = b.getClass();
- System.out.println(a == b); //true
上面程序的輸出結果為true。所有反射的操作都是在運行時的,既然為true,就證明了編譯之後,程序會采取去泛型化的措施,也就是說Java中的泛型,只在編譯階段有效。在編譯過程中,正確檢驗泛型結果後,會將泛型的相關信息擦出,並且在對象進入和離開方法的邊界處添加類型檢查和類型轉換的方法。也就是說,成功編譯過後的class文件中是不包含任何泛型信息的。泛型信息不會進入到運行時階段。
上述結論可通過下面反射的例子來印證:
- ArrayList<String> a = new ArrayList<String>();
- a.add("CSDN_SEU_Cavin");
- Class c = a.getClass();
- try{
- Method method = c.getMethod("add",Object.class);
- method.invoke(a,100);
- System.out.println(a);
- }catch(Exception e){
- e.printStackTrace();
- }
因為繞過了編譯階段也就繞過了泛型,輸出結果為:
- [CSDN_SEU_Cavin, 100]
4.泛型類和泛型方法
如下,我們看一個泛型類和方法的使用例子,和未使用泛型的使用方法進行了對比,兩者輸出結果相同,在這裏貼出來方便讀者體會兩者的差異。泛型接口的例子有興趣可以去找一些資料,這裏就不贅述了。
(1)使用泛型的情況
- public static class FX<T> {
- private T ob; // 定義泛型成員變量
- public FX(T ob) {
- this.ob = ob;
- }
- public T getOb() {
- return ob;
- }
- public void showTyep() {
- System.out.println("T的實際類型是: " + ob.getClass().getName());
- }
- }
- public static void main(String[] args) {
- FX<Integer> intOb = new FX<Integer>(100);
- intOb.showTyep();
- System.out.println("value= " + intOb.getOb());
- System.out.println("----------------------------------");
- FX<String> strOb = new FX<String>("CSDN_SEU_Calvin");
- strOb.showTyep();
- System.out.println("value= " + strOb.getOb());
- }
(2)不使用泛型的情況
- public static class FX {
- private Object ob; // 定義泛型成員變量
- public FX(Object ob) {
- this.ob = ob;
- }
- public Object getOb() {
- return ob;
- }
- public void showTyep() {
- System.out.println("T的實際類型是: " + ob.getClass().getName());
- }
- }
- public static void main(String[] args) {
- FX intOb = new FX(new Integer(100));
- intOb.showTyep();
- System.out.println("value= " + intOb.getOb());
- System.out.println("----------------------------------");
- FX strOb = new FX("CSDN_SEU_Calvin");
- strOb.showTyep();
- System.out.println("value= " + strOb.getOb());
- }
輸出結果均為:
- T的實際類型是: java.lang.Integer
- value= 100
- ----------------------------------
- T的實際類型是: java.lang.String
- value= CSDN_SEU_Calvin
5.通配符
為了引出通配符的概念,先看如下代碼:
- List<Integer> ex_int= new ArrayList<Integer>();
- List<Number> ex_num = ex_int; //非法的
上述第2行會出現編譯錯誤,因為Integer雖然是Number的子類,但List<Integer>不是List<Number>的子類型。
假定第2行代碼沒有問題,那麽我們可以使用語句ex_num.add(newDouble())在一個List中裝入了各種不同類型的子類,這顯然是不可以的,因為我們在取出List中的對象時,就分不清楚到底該轉型為Integer還是Double了。
因此,我們需要一個在邏輯上可以用來同時表示為List<Integer>和List<Number>的父類的一個引用類型,類型通配符應運而生。在本例中表示為List<?>即可。下面這個例子也說明了這一點,註釋已經寫的很清楚了。
- public static void main(String[] args) {
- FX<Number> ex_num = new FX<Number>(100);
- FX<Integer> ex_int = new FX<Integer>(200);
- getData(ex_num);
- getData(ex_int);//編譯錯誤
- }
- public static void getData(FX<Number> temp) { //此行若把Number換為“?”編譯通過
- //do something...
- }
- public static class FX<T> {
- private T ob;
- public FX(T ob) {
- this.ob = ob;
- }
- }
what are you 弄啥嘞!!!!!!!!!!!!!!!!泛型