Java 泛型詳解

首先在沒有泛型之前,一旦把一個對象丟進java集合中,集合就會忘記對象的類型,把所有對象當成Object類型來處理。當程序從集合中取出對象時,就需要進行強制類型轉換,這種強制類型轉換不僅代碼臃腫,而且容易引起ClassCastException異常。

    public class ListErr
    {
        public static void main(String[] args) 
        {
            //創建一個只想保存字符串的List集合
            List strList = new ArrayList();
            strList.add("Struts2權威指南");
            strList.add("基於J2EE的Ajax寶典");
            strList.add("輕量級J2EE企業應用實戰");
            //”不小心“把一個Integer對象”丟進"了集合
            strList.add(5);
            for (int i = 0; i < strList.size() ; i++ )
            {
                //因爲List裏取出的全部是Object,所以必須強制類型轉換
                //最後一個元素將出現ClassCastException異常
                String str = (String)strList.get(i);
            }
        }
    }

爲了解決這個問題,在1.5前都採用,創建個List對象的方法,但每遇到個集合都要建個對象,eg

    class StrList
    {
        private List strList = new ArrayList();
        //定義StrList的add方法
        public boolean add(String ele)
        {
            return strList.add(ele);
        }
        //重寫get方法,將get方法的返回值類型改爲String類型
        public String get(int index)
        {
            return (String)strList.get(index);
        }
        public int size()
        {
            return strList.size();
        }
    }

public class CheckType
{
    public static void main(String[] args) 
    {
        //創建一個只想保存字符串的List集合
        StrList strList = new StrList();
        strList.add("Struts2權威指南");
        strList.add("基於J2EE的Ajax寶典");
        strList.add("輕量級J2EE企業應用實戰");
        //下面語句不能把Integer對象“丟進”集合中,將引起編譯異常
        strList.add(5);
        System.out.println(strList);
        for (int i = 0; i < strList.size() ; i++ )
        {
            //因爲StrList裏元素的類型就是String類型,所以無需強制類型轉換
            String str = strList.get(i);
        }
    }
}
有了泛型就方便了,eg

    public class GenericList
    {
        public static void main(String[] args) 
        {
            //創建一個只想保存字符串的List集合
            List<String> strList = new ArrayList<String>();
            strList.add("Struts2權威指南");
            strList.add("基於J2EE的Ajax寶典");
            strList.add("輕量級J2EE企業應用實戰");
            //下面代碼將引起編譯錯誤
            strList.add(5);
            for (int i = 0; i < strList.size() ; i++ )
            {
                //下面代碼無需強制類型轉換
                String str = strList.get(i);
            }
        }
    }

當創建帶泛型的自定義類時,在定義該類構造器時,構造器名還是和類名一樣,不要增加泛型聲明。

從泛型類派生子類,接口,父類不能包含類型形參。

下面例子就是錯誤的。

public class A extends B<T>{},

使用類型通配符“?’”, 它可以匹配任何類型,

public void test(List <?>){}


使用時注意:List<String>不是List<Object>子類

特殊的泛型(帶類型通配符和類型上限),eg

    public class Apple<T extends Number>
    {
        T col;
        
        public static void main(String[] args)
        {
            Apple<Integer> ai = new Apple<Integer>();
            Apple<Double> ad = new Apple<Double>();
            //下面代碼將引起編譯異常
            //因爲String類型傳給T形參,但String不是Number的子類型。
            Apple<String> as = new Apple<String>();
            
        }
    }

java泛型不支持泛型數組(List<String> aa=new ArrayList<String>[10];),因爲java泛型的設計原則是沒有unchecked警告就沒有ClassCastExcepiton. 我建議大家遇到集合數組等的時候,自己來檢驗數據的類型,eg

    public class test {
        public static void main(String[] args) {
            ArrayList[] aa = new ArrayList[10];
            List<Integer> li = new ArrayList<Integer>();
            li.add(3);
            ((Object[]) aa)[1] = li;
            Object target = aa[1].get(0);
            if (target instanceof Integer) {
                Integer s = (Integer) target;
                System.out.println(s);
            }
        }
    }

由於java的泛型只是編譯時做下檢驗,大家不要想的過於強大,他的最大作用只是增強代碼的可讀性,別的方面也沒見多大的作用。

什麼時候寫泛型?有什麼好處?

最簡單的體現,只要使用到了帶有<>的類和接口,就指定具體對象類型。

 

泛型的好處:

1,  將運行時出現的ClassCastException問題,再編譯時期給解決了。運行就安全了。

2,  避免了強制轉換的麻煩。

 

所以泛型就是JDK1.5後出現的一個安全機制。


泛型的理解?

首先在沒有泛型之前,一旦把一個對象丟進java集合中,集合就會忘記對象的類型,把所有對象當成Object類型來處理。

         當程序從集合中取出對象時,就需要進行強制類型轉換,這種強制類型轉換不僅代碼臃腫,而且容易引起ClassCastException異常。

         1,泛型就是傳參數。

2,泛型替代了Object。


什麼是泛型的擦除和補償?

泛型是編譯時期的安全機制。

         編譯時,通過泛型機制,編譯器多了多元素類型進行檢查的步驟。

         如果檢查通過,產生的class文件時不帶有泛型的:也就是泛型的擦除。

 

         泛型的補償:在對元素存儲的時候,可以完成類型的判斷。

                                     可是在對元素取出的時候,怎麼用指定的類型來接收呢?

                                     JVM運行時,會獲取元素的類型,並用該類型對元素進行轉換即可。


什麼時候使用泛型類?

當類中要操作的引用數據類型不確定的時候,以前使用的是共性類型Object,

現在可以使用泛型來解決。


什麼時候使用泛型方法?

當方法操作的引用數據類型不確定的時候,就使用泛型方法。

 

如果方法是靜態的,是無法訪問類上定義的泛型的。

如果該方法還需要泛型。

必須將泛型定義在方法上。


泛型的限定。

如果要對操作的類型進行限定,只操作一部分類型時,可以使用泛型的高級功能。

?extends E:可以接收E類型和E的子類型。這叫泛型的上限。

?super E:可以接收E類型或E的父類型。這叫泛型的下限。


什麼時候會用? extends E 呢?(往集合中添加集合的時候經常使用)

一般在存儲具體引用類型時,使用這種情況。

因爲存儲E類型或者E類型的子類型,在取出的時候都可以用E類型來操作這些元素。

這時可以保證類型是安全的。


下限什麼時候用?

從集合中取出對象進行操作時,可以使用下限。

例如:比較器。無論集合中的元素對象的類型是什麼,只要比較器的指定的類型可以接收這些對象完成比較,就可以了。

所以比較器的類型,可以是集合中當前元素的類型,也可以是該元素類型的父類型。


泛型使用的誤區:

1,  凡是安全的都特別嚴格。一定要保證座左右兩邊一致。

2, 不能操作特有對象。

參數定義的集合類型是一個範圍,而接受的實際參數是以一個實體,該實體肯定會指定該範圍中的某一個具體類型。而該類型是創建容器時指定的,到底是哪種類型該方法是不確定的,那麼就不可以在該方法內,進行具體類型對象的定義和操作。

 建議定義泛型時,左右兩邊一定要一致。如果不一致要保證一點,左邊在聲明時可以聲明一個類型範圍,右邊在實例化時指定的具體類型必須是左邊類型範圍中的一種。




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