JDK5.0新特性的學習--泛型(下)
既然在J2SE 5.0中收集型別已經泛型化,那麼,原來的使用這些型別的程式碼將如何呢?很幸運,他們在JAVA 5中將繼續工作,因為你能使用沒有引數的泛型。比如,你能繼續像原來一樣使用List介面,正如下面的例子一樣。
List stringList1 = new ArrayList();一個沒有任何引數的泛型被稱為原型(raw type)。它意味著這些為JDK1.4或更早的版本而寫的程式碼將繼續在java 5中工作。
stringList1.add("Java 1.0 - 5.0");
stringList1.add("without generics");
String s1 = (String) stringList1.get(0);
儘管如此,一個需要注意的事情是,JDK5編譯器希望你使用帶引數的泛型。否則,編譯器將提示警告,因為他認為你可能忘了定義型別變數s。比如,編譯上面的程式碼的時候你會看到下面這些警告,因為第一個List被認為是原型。
Note: com/brainysoftware/jdk5/app16/GenericListTest.java
uses unchecked or unsafe operations.
Note: Recompile with -Xlint:unchecked for details.
當你使用原型時,如果你不想看到這些警告,你有幾個選擇來達到目的:
1.編譯時帶上引數-source 1.4
2.使用@SupressWarnings("unchecked")註釋
3.更新你的程式碼,使用List. List的例項能接受任何型別的物件,就像是一個原型List。然而,編譯器不會報錯。
使用 ? 萬用字元
前面提過,如果你宣告瞭一個List
1.一個aType的例項
2.它的子類的例項(如果aType是個類)
3.實現aType介面的類例項(如果aType是個介面)
但是,請注意,一個泛型本身是個JAVA型別,就像java.lang.String或java.io.File一樣。傳遞不同的型別變數給泛型可以建立不同的JAVA型別。比如,下面例子中list1和list2引用了不同的型別物件。
Listlist1 = new ArrayList();
List
list1指向了一個型別變數s為java.lang.Objects 的List而list2指向了一個型別變數s為String 的List。所以傳遞一個List
public class AllowedTypeTest {
public static void doIt(Listl) {
}
public static void main(String[] args) {
List
// 這裡將產生一個錯誤
doIt(myList);
}
}
上面的程式碼無法編譯,因為你試圖傳遞一個錯誤的型別給函式doIt。doIt的引數是List二你傳遞的引數是List
可以使用 ? 萬用字元解決這個難題。List 意味著一個對任何物件起作用的List。所以,doIt可以改為:
public static void doIt(List l) {}
在某些情況下你會考慮使用 ? 萬用字元。比如,你有一個printList函式,這個函式列印一個List的所有成員,你想讓這個函式對任何型別的List起作用時。否則,你只能累死累活的寫很多printList的過載函式。下面的列表引用了使用 ? 萬用字元的printList函式。
public class WildCardTest {
public static void printList(List list) {
for (Object element : list) {
System.out.println(element);
}
}
public static void main(String[] args) {
List
list1.add("Hello");
list1.add("World");
printList(list1);
List
list2.add(100);
list2.add(200);
printList(list2);
}
}
這些程式碼說明了在printList函式中,List表示各種型別的List物件。然而,請注意,在宣告的時候使用 ? 萬用字元是不合法的,像這樣:
List myList = new ArrayList(); // 不合法
ListmyList = new ArrayList();
在函式中使用界限萬用字元
在之前的章節中,你學會了透過傳遞不同的型別變數s來建立不同JAVA型別的泛型,但並不考慮型別變數s之間的繼承關係。在很多情況下,你想一個函式有不同的List引數。比如,你有一個函式getAverage,他返回了一個List中成員的平均值。然而,如果你把List
你能使用原型或使用萬用字元,但這樣無法在編譯時進行安全型別檢查,因為你能傳遞任何型別的List,比如List
J2SE5.0增加了一個規則來解決了這種約束,這個規則就是允許你定義一個上界(upper bound) 型別變數.在這種方式中,你能傳遞一個型別或它的子類。在上面getAverage函式的例子中,你能傳遞一個List
使用上界規則的語法這麼定義的:GenericType<!--xtends upperBoundTy-->. 比如,對getAverage函式的引數,你可以這麼寫List<!--xtends Numb-->. 下面例子說明了如何使用這種規則。
public class BoundedWildcardTest {由於有了上界規則,上面例子中的getAverage函式允許你傳遞一個List
public static double getAverage(List<!--xtends Numb--> numberList)
{
double total = 0.0;
for (Number number : numberList)
total += number.doubleValue();
return total/numberList.size();
}
public static void main(String[] args) {
ListintegerList = new ArrayList ();
integerList.add(3);
integerList.add(30);
integerList.add(300);
System.out.println(getAverage(integerList)); // 111.0
ListdoubleList = new ArrayList ();
doubleList.add(3.0);
doubleList.add(33.0);
System.out.println(getAverage(doubleList)); // 18.0
}
}
下界規則
關鍵字extends定義了一個型別變數的上界。透過使用super關鍵字,我們可以定義一個型別變數的下界,儘管使用的情況不多。比如,如果一個函式的引數是List<!--uper Integ-->,那麼意味著你可以傳遞一個List
建立泛型
前面的章節主要說明了如何使使用泛型,特別是集合框架中的類。現在我們開始學習如何寫自己的泛型。
基本上,除了宣告一些你想要使用的型別變數s外,一個泛型和別的類沒有什麼區別。這些型別變數s位於型別後面的<>中。比如,下面的Point就是個泛型。一個Point物件代表了一個系統中的點,它有橫座標和縱座標。透過使Point泛型化,你能定義一個點例項的精確程度。比如,如果一個Point物件需要非常精確,你就把Double作為型別變數。否則,Integer 就夠了。
package com.brainysoftware.jdk5.app16;在這個例子中,T是Point的型別變數 。T是getX和getY的返回值型別,也是setX和setY的引數型別。此外,建構函式結合兩個T引數。
public class Point{
T x;
T y;
public Point(T x, T y) {
this.x = x;
this.y = y;
}
public T getX() {
return x;
}
public T getY() {
return y;
}
public void setX(T x) {
this.x = x;
}
public void setY(T y) {
this.y = y;
}
}
使用point類就像使用別的類一樣。比如,下面的例子建立了兩個Point物件:ponint1和point2。前者把Integer作為型別變數,而後者把Double作為型別變數。
Point總結point1 = new Point (4, 2);
point1.setX(7);
Pointpoint2 = new Point (1.3, 2.6);
point2.setX(109.91);
泛型使程式碼在編譯時有了更嚴格的型別檢查。特別是在集合框架中,泛型有兩個作用。第一,他們增加了對集合型別在編譯時的型別檢查,所以集合類所能持有的型別對傳遞給它的引數型別起了限制作用。比如你建立了一個持有strings的java.util.List例項,那麼他就將不能接受Integers或別的型別。其次,當你從一個集合中取得一個元素時,泛型消除了型別轉換的必要。
泛型能夠在沒有型別變數的情況下使用,比如,作為原型。這些措施讓Java 5之前的程式碼能夠執行在JRE 5中。但是,對新的應用程式,你最好不要使用原型,因為以後Java可能不支援他們。
你已經知道透過傳遞不同型別的型別變數給泛型可以產生不同的JAVA型別。就是說List
最後,你已經看到了寫一個泛型和別的一般JAVA類沒有什麼區別。你只需要在型別名稱後面的<>中宣告一系列的型別變數s就行了。這些型別變數s就是返回值型別或者引數型別。根據慣例,一個型別變數用一個大寫字母表示。[@more@]
來自 “ ITPUB部落格 ” ,連結:http://blog.itpub.net/800861/viewspace-922110/,如需轉載,請註明出處,否則將追究法律責任。
相關文章
- JDK5.0新特性的學習--泛型(上)JDK泛型
- JDK5.0新特性的學習--列舉JDK
- JDK5.0新特性的學習--後設資料JDK
- JDK5.0新特性的學習--靜態匯入JDK
- JDK5.0新特性的學習--可變長引數JDK
- 學習Rust泛型與特性Rust泛型
- JDK5.0新特性之:列舉JDK
- Java高階特性之泛型學習總結Java泛型
- C#泛型學習C#泛型
- 泛型學習筆記泛型筆記
- java泛型學習(1)Java泛型
- Rust 泛型與特性Rust泛型
- Java JDK1.5: 泛型 新特性的講解說明JavaJDK泛型
- Java高階特性—泛型Java泛型
- TypeScript學習(四)—— 介面和泛型TypeScript泛型
- 第 80 期帶你提前玩 Go 2 新特性:泛型Go泛型
- C#學習 [型別系統] 泛型(16)C#型別泛型
- rust學習十一.1、泛型(通用型別)Rust泛型型別
- java入門基礎學習----泛型Java泛型
- java基礎學習之十三:泛型Java泛型
- Java隨筆-Java泛型的一點學習Java泛型
- JDK 1.8 新特性學習(Stream)JDK
- Java1.8新特性學習Java
- java8新特性學習Java
- .NET泛型解析(下)泛型
- 深圳大資料學習:泛型--【千鋒】大資料泛型
- iOS學習筆記47 Swift(七)泛型iOS筆記Swift泛型
- Java泛型複習Java泛型
- Go型別特性-學習筆記Go型別筆記
- JAVA泛型使用練習2(自定義泛型使用)Java泛型
- C++ 11 新特性 nullptr 學習C++Null
- JDK11新特性學習(一)JDK
- JDK11新特性學習(二)JDK
- 學習 Java,你不得不知的泛型知識Java泛型
- Java進階學習之集合與泛型(1)Java泛型
- 泛型--泛型萬用字元和泛型的上下限泛型字元
- Automatic Reference Counting(ARC)特性學習(iOS5新特性學習之五)iOS
- jdk-1.8新特性學習筆記JDK筆記