C語言中文網 目錄

Java泛型詳解:Java泛型集合、泛型類、泛型方法、泛型的使用

Java 1.5 之前沒有泛型,通常需要使用強制類型轉換的方式將一種數據類型轉換為另一種數據類型,這種轉換要求開發者對實際參數的類型具有可預知性。對于強制類型轉換錯誤的情況,編譯器可能不會提示錯誤,但是在運行時會出現異常,這是一個安全隱患。

為了解決這一隱患,從 Java 1.5 開始提供了泛型。泛型可以在編譯的時候檢查類型安全,并且所有的強制轉換都是自動和隱式的,提高了代碼的重用率。本節將詳細介紹 Java 中泛型的使用。

泛型集合

泛型本質上是提供類型的“類型參數”,也就是參數化類型。我們可以為類、接口或方法指定一個類型參數,通過這個參數限制操作的數據類型,從而保證類型轉換的絕對安全。

例 1

下面將結合泛型與集合編寫一個案例實現圖書信息輸出。

(1) 首先需要創建一個表示圖書的實體類 Book,其中包括的圖書信息有圖書編號、圖書名稱和價格。Book 類的具體代碼如下:
public class Book
{
    private int Id;    //圖書編號
    private String Name;    //圖書名稱
    private int Price;    //圖書價格
    public Book(int id,String name,int price)
    {    //構造方法
        this.Id=id;
        this.Name=name;
        this.Price=price;
    }
    public String toString()
    {    //重寫 toString()方法
        return this.Id+", "+this.Name+","+this.Price;
    }
}

(2) 使用 Book 作為類型創建 Map 和 List 兩個泛型集合,然后向集合中添加圖書元素,最后輸出集合中的內容。具體代碼如下:
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class Test14
{
    public static void main(String[] args)
    {
        //創建3個Book對象
        Book book1=new Book(1,"唐詩三百首",8);
        Book book2=new Book(2,"小星星",12);
        Book book3=new Book(3,"成語大全",22);
        Map<Integer,Book> books=new HashMap<Integer,Book>();    //定義泛型 Map 集合
        books.put(1001,book1);    //將第一個 Book 對象存儲到 Map 中
        books.put(1002,book2);    //將第二個 Book 對象存儲到 Map 中
        books.put(1003,book3);    //將第三個 Book 對象存儲到 Map 中
        System.out.println("泛型Map存儲的圖書信息如下:");
        for(Integer id:books.keySet())
        {
            //遍歷鍵
            System.out.print(id+"——");
            System.out.println(books.get(id));    //不需要類型轉換
        }
        List<Book> bookList=new ArrayList<Book>();    //定義泛型的 List 集合
        bookList.add(book1);
        bookList.add(book2);
        bookList.add(book3);
        System.out.println("泛型List存儲的圖書信息如下:");
        for(int i=0;i<bookList.size();i++)
        {
            System.out.println(bookList.get(i));    //這里不需要類型轉換
        }
    }
}

在該示例中,代碼“Map<Integer,Book> books=new HashMap<Integer,Book>();”創建了一個鍵類型為 Integer、值類型為 Book 的泛型集合,即指明了該 Map 集合中存放的鍵必須是 Integer 類型、值必須為 Book 類型,否則編譯出錯。在獲取 Map 集合中的元素時,不需要將"books.get(id);"獲取的值強制轉換為 Book 類型,程序會隱式轉換。在創建 List 集合時,同樣使用了泛型,因此在獲取集合中的元素時也不需要將“bookList.get(i)”代碼強制轉換為 Book 類型,程序會隱式轉換。

執行結果如下:
泛型Map存儲的圖書信息如下:
1001——1, 唐詩三百首,8
1003——3, 成語大全,22
1002——2, 小星星,12
泛型List存儲的圖書信息如下:
1, 唐詩三百首,8
2, 小星星,12
3, 成語大全,22

泛型類

除了可以定義泛型集合之外,還可以直接限定泛型類的類型參數。語法格式如下:
public class class_name<data_type1,data_type2,…>{}
其中,class_name 表示類的名稱,data_ type1 等表示類型參數。Java 泛型支持聲明一個以上的類型參數,只需要將類型用逗號隔開即可。

泛型類一般用于類中的屬性類型不確定的情況下。在聲明屬性時,使用下面的語句:
private data_type1 property_name1;
private data_type2 property_name2;
該語句中的 data_type1 與類聲明中的 datajype1 表示的是同一種數據類型。

例 2

在實例化泛型類時,需要指明泛型類中的類型參數,并賦予泛型類屬性相應類型的值。例如,下面的示例代碼創建了一個表示學生的泛型類,該類中包括 3 個屬性,分別是姓名、年齡和性別。
public class Stu<N,A,S>
{
    private N name;    //姓名
    private A age;    //年齡
    private S sex;    //性別
    //創建類的構造函數
    public Stu(N name,A age,S sex)
    {
        this.name=name;
        this.age=age;
        this.sex=sex;
    }
    //下面是上面3個屬性的setter/getter方法
    public N getName()
    {
        return name;
    }
    public void setName(N name)
    {
        this.name=name;
    }
    public A getAge()
    {
        return age;
    }
    public void setAge(A age)
    {
        this.age = age;
    }
    public S getSex()
    {
        return sex;
    }
    public void setSex(S sex)
    {
        this.sex=sex;
    }
}

接著創建測試類。在測試類中調用 Stu 類的構造方法實例化 Stu 對象,并給該類中的 3 個屬性賦予初始值,最終需要輸出學生信息。測試類的代碼實現如下:
public class Test14
{
    public static void main(String[] args)
    {
        Stu<String,Integer,Character> stu=new Stu<String,Integer,Character>("張曉玲",28,'女');
        String name=stu.getName();
        Integer age=stu.getAge();
        Character sex=stu.getSex();
        System.out.println("學生信息如下:");
        System.out.println("學生姓名:"+name+",年齡:"+age+",性別:"+sex);
    }
}

該程序的運行結果如下:
學生信息如下:
學生姓名:張曉玲,年齡:28,性別:女

在該程序的 Stu 類中,定義了 3 個類型參數,分別使用 N、A 和 S 來代替,同時實現了這 3 個屬性的 setter/getter 方法。在主類中,調用 Stu 類的構造函數創建了 Stu 類的對象,同時指定 3 個類型參數,分別為 String、Integer 和 Character。在獲取學生姓名、年齡和性別時,不需要類型轉換,程序隱式地將 Object 類型的數據轉換為相應的數據類型。

泛型方法

到目前為止,我們所使用的泛型都是應用于整個類上。泛型同樣可以在類中包含參數化的方法,而方法所在的類可以是泛型類,也可以不是泛型類。也就是說,是否擁有泛型方法,與其所在的類是不是泛型沒有關系。

泛型方法使得該方法能夠獨立于類而產生變化。如果使用泛型方法可以取代類泛型化,那么就應該只使用泛型方法。另外,對一個 static 的方法而言,無法訪問泛型類的類型參數。因此,如果 static 方法需要使用泛型能力,就必須使其成為泛型方法。

定義泛型方法的語法格式如下:
[訪問權限修飾符][static][final]<類型參數列表>返回值類型方法名([形式參數列表])
例如:
public static List<T> find(Class<T>class,int userId){}

一般來說編寫 Java 泛型方法,其返回值類型至少有一個參數類型應該是泛型,而且類型應該是一致的,如果只有返回值類型或參數類型之一使用了泛型,那么這個泛型方法的使用就被限制了。下面就來定義一個泛型方法,具體介紹泛型方法的創建和使用。

例 3

使用泛型方法打印圖書信息。定義泛型方法,參數類型使用“T”來代替。在方法的主體中打印出圖書信息。代碼的實現如下:
public class Test16
{
    public static<T> void List(T book)
    {    //定義泛型方法
        if(book!=null)
        {
            System.out.println(book);
        }
    }
    public static void main(String[] args)
    {
        Book stu=new Book(1,"細學 Java 編程",28);
        List(stu);    //調用泛型方法
    }
}

該程序中的 Book 類為前面示例中使用到的 Book 類。在該程序中定義了一個名稱為 List 的方法,該方法的返回值類型為 void,類型參數使用“T”來代替。在調用該泛型方法時,將一個 Book 對象作為參數傳遞到該方法中,相當于指明了該泛型方法的參數類型為 Book。

該程序的運行結果如下:
1, 細學 Java 編程,28

泛型的高級用法

泛型的用法非常靈活,除在集合、類和方法中使用外,本節將從三個方面介紹泛型的高級用法,包括限制泛型可用類型、使用類型通配符、繼承泛型類和實現泛型接口。

1. 限制泛型可用類型

在 Java 中默認可以使用任何類型來實例化一個泛型類對象。當然也可以對泛型類實例的類型進行限制,語法格式如下:
class 類名稱<T extends anyClass>

其中,anyClass 指某個接口或類。使用泛型限制后,泛型類的類型必須實現或繼承 anyClass 這個接口或類。無論 anyClass 是接口還是類,在進行泛型限制時都必須使用 extends 關鍵字。

例如,在下面的示例代碼中創建了一個 ListClass 類,并對該類的類型限制為只能是實現 List 接口的類。
//限制ListClass的泛型類型必須實現List接口
public class ListClass<T extends List>
{
    public static void main(String[] args)
    {
        //實例化使用ArrayList的泛型類ListClass,正確
        ListClass<ArrayList> lc1=new ListClass<ArrayList>();
        //實例化使用LinkedList的泛型類LlstClass,正確
        ListClass<LinkedList> lc2=new ListClass<LinkedList>();
        //實例化使用HashMap的泛型類ListClass,錯誤,因為HasMap沒有實現List接口
        //ListClass<HashMap> lc3=new ListClass<HashMap>();
    }
}

在上述代碼中,定義 ListClass 類時設置泛型類型必須實現 List 接口。例如,ArrayList 和 LinkedList 都實現了 List 接口,所以可以實例化 ListClass 類。而 HashMap 沒有實現 List 接口,所以在實例化 ListClass 類時會報錯。

當沒有使用 extends 關鍵字限制泛型類型時,其實是默認使用 Object 類作為泛型類型。因此,Object 類下的所有子類都可以實例化泛型類對象,如圖 1 所示的這兩種情況。


圖1 兩個等價的泛型類

2. 使用類型通配符

Java 中的泛型還支持使用類型通配符,它的作用是在創建一個泛型類對象時限制這個泛型類的類型必須實現或繼承某個接口或類。

使用泛型類型通配符的語法格式如下:
泛型類名稱<? extends List>a=null;
其中,“<? extends List>”作為一個整體表示類型未知,當需要使用泛型對象時,可以單獨實例化。

例如,下面的示例代碼演示了類型通配符的使用。
A<? extends List>a=null;
a=new A<ArrayList> ();    //正確
b=new A<LinkedList> ();    //正確
c=new A<HashMap> ();    //錯誤
在上述代碼中,同樣由于 HashMap 類沒有實現 List 接口,所以在編譯時會報錯。

3. 繼承泛型類和實現泛型接口

定義為泛型的類和接口也可以被繼承和實現。例如下面的示例代碼演示了如何繼承泛型類。
public class FatherClass<T1>{}
public class SonClass<T1,T2,T3> extents FatherClass<T1>{}

如果要在 SonClass 類繼承 FatherClass 類時保留父類的泛型類型,需要在繼承時指定,否則直接使用 extends FatherClass 語句進行繼承操作,此時 T1、T2 和 T3 都會自動變為 Object,所以一般情況下都將父類的泛型類型保留。

下面的示例代碼演示了如何在泛型中實現接口。
interface interface1<T1>{}
interface SubClass<T1,T2,T3> implements
Interface1<T2>{}

精美而實用的網站,提供C語言C++STLLinuxShellJavaGo語言等教程,以及socketGCCviSwing設計模式JSP等專題。

Copyright ?2011-2018 biancheng.net, 陜ICP備15000209號

底部Logo