小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

Java泛型簡明教程

 碼農(nóng)9527 2021-09-24

  前面我們提到Java集合有個缺點,就是把一個對象“丟進”集合里之后,集合就會“忘記”這個對象的數(shù)據(jù)類型,當再次取出該對象時,該對象的編譯類型就變成了Object類型(其運行時類型沒變)。

    Java集合之所以被設(shè)計成這樣,是因為集合的設(shè)計者不知道我們會用集合來保存什么類型的對象,所以他們把集合設(shè)計成能保存任何類型的對象,只要求具有很好的通用性,但這樣做帶來如下兩個問題:

    1、集合對元素類型沒有任何限制,這樣可能引發(fā)一些問題。例如,想創(chuàng)建一個只能保存Dog對象的集合,但程序也可以輕易地將Cat對象“丟”進去,所以可能引發(fā)異常。

    2、由于把對象“丟進”集合時,集合丟失了對象的狀態(tài)信息,集合只知道它盛裝的是Object,因此取出集合元素后通常還需要進行強制類型轉(zhuǎn)換。這種強制類型轉(zhuǎn)換既增加了編程的復雜度,也可能引發(fā)ClassCastException異常。

    所以為了解決上述問題,從Java1.5開始提供了泛型。泛型可以在編譯的時候檢查類型安全,并且所有的強制轉(zhuǎn)換都是自動和隱式的,提高了代碼的重用率。本節(jié)將詳細介紹Java中泛型的使用。

    泛型集合

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

    例1

    下面將結(jié)合泛型與集合編寫一個案例實現(xiàn)圖書信息輸出。

    1)首先需要創(chuàng)建一個表示圖書的實體類Book,其中包括的圖書信息有圖書編號、圖書名稱和價格。Book類的具體代碼如下:

public class Book { private int Id; // 圖書編號
 private String Name; // 圖書名稱
 private int Price; // 圖書價格
 public Book(int id, String name, int price) { // 構(gòu)造方法
  this.Id = id;  this.Name = name;  this.Price = price;
 } public String toString() { // 重寫 toString()方法
  return this.Id + ", " + this.Name + "," + this.Price;
 }
}12345678910111213復制代碼類型:[java]

    2)使用Book作為類型創(chuàng)建Map和List兩個泛型集合,然后向集合中添加圖書元素,最后輸出集合中的內(nèi)容。具體代碼如下:

public class Test14 { public static void main(String[] args) {  // 創(chuàng)建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)); // 不需要類型轉(zhuǎn)換
  }
  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)); // 這里不需要類型轉(zhuǎn)換
  }
 }
}123456789101112131415161718192021222324252627復制代碼類型:[java]

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

    執(zhí)行結(jié)果如下:

泛型Map存儲的圖書信息如下:1001——1, 唐詩三百首,81003——3, 成語大全,221002——2, 小星星,12泛型List存儲的圖書信息如下:1, 唐詩三百首,82, 小星星,123, 成語大全,2212345678復制代碼類型:[java]

    泛型類

    除了可以定義泛型集合之外,還可以直接限定泛型類的類型參數(shù)。語法格式如下:

public class class_name<data_type1,data_type2,…>{}1復制代碼類型:[java]

    其中,class_name表示類的名稱,data_type1等表示類型參數(shù)。Java泛型支持聲明一個以上的類型參數(shù),只需要將類型用逗號隔開即可。

    泛型類一般用于類中的屬性類型不確定的情況下。在聲明屬性時,使用下面的語句:

private data_type1 property_name1;private data_type2 property_name2;12復制代碼類型:[java]

    該語句中的data_type1與類聲明中的data_type1表示的是同一種數(shù)據(jù)類型。

    例2

    在實例化泛型類時,需要指明泛型類中的類型參數(shù),并賦予泛型類屬性相應類型的值。例如,下面的示例代碼創(chuàng)建了一個表示學生的泛型類,該類中包括3個屬性,分別是姓名、年齡和性別。

public class Stu<N, A, S> { private N name; // 姓名
 private A age; // 年齡
 private S sex; // 性別
 // 創(chuàng)建類的構(gòu)造函數(shù)
 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;
 }
}123456789101112131415161718192021222324252627282930復制代碼類型:[java]

    接著創(chuàng)建測試類。在測試類中調(diào)用Stu類的構(gòu)造方法實例化Stu對象,并給該類中的3個屬性賦予初始值,最終需要輸出學生信息。測試類的代碼實現(xiàn)如下: 

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);
 }
}12345678910復制代碼類型:[java]

    該程序的運行結(jié)果如下:

學生信息如下:
學生姓名:張曉玲,年齡:28,性別:女12復制代碼類型:[java]

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

    泛型方法

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

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

    定義泛型方法的語法格式如下:

[訪問權(quán)限修飾符] [static] [final] <類型參數(shù)列表> 返回值類型 方法名([形式參數(shù)列表])1復制代碼類型:[java]

    例如:

public static <T> List find(Class<T> cs,int userId){}1復制代碼類型:[java]

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

    例3

    使用泛型方法打印圖書信息。定義泛型方法,參數(shù)類型使用“T”來代替。在方法的主體中打印出圖書信息。代碼的實現(xiàn)如下:

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); // 調(diào)用泛型方法
 }
}1234567891011復制代碼類型:[java]

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

    該程序的運行結(jié)果如下:

1, 細學 Java 編程,281復制代碼類型:[java]

    泛型的高級用法

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

    1.限制泛型可用類型

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

class 類名稱<T extends anyClass>1復制代碼類型:[java]

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

    例如,在下面的示例代碼中創(chuàng)建了一個ListClass類,并對該類的類型限制為只能是實現(xiàn)List接口的類。

// 限制ListClass的泛型類型必須實現(xiàn)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沒有實現(xiàn)List接口
  // ListClass<HashMap> lc3=new ListClass<HashMap>();
 }
}123456789101112復制代碼類型:[java]

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

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

    2.使用類型通配符

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

    使用泛型類型通配符的語法格式如下:

泛型類名稱<? extends List>a = null;1復制代碼類型:[java]

    其中,“<?extendsList>”作為一個整體表示類型未知,當需要使用泛型對象時,可以單獨實例化。

    例如,下面的示例代碼演示了類型通配符的使用。

A<? extends List>a = null;
a = new A<ArrayList> (); // 正確b = new A<LinkedList> (); // 正確c = new A<HashMap> (); // 錯誤1234復制代碼類型:[java]

    在上述代碼中,同樣由于HashMap類沒有實現(xiàn)List接口,所以在編譯時會報錯。

    3.繼承泛型類和實現(xiàn)泛型接口

    定義為泛型的類和接口也可以被繼承和實現(xiàn)。例如下面的示例代碼演示了如何繼承泛型類。

public class FatherClass<T1>{}public class SonClass<T1,T2,T3> extents FatherClass<T1>{}12復制代碼類型:[java]

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

    下面的示例代碼演示了如何在泛型中實現(xiàn)接口。

interface interface1<T1>{}interface SubClass<T1,T2,T3> implementsInterface1<T2>{}

    轉(zhuǎn)藏 分享 獻花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多