Java泛型總結報告精選
Java泛型總結報告精選
篇一:Java泛型總結
1. 什麼是泛型?
泛型(Generic type 或者 generics)是對 Java 語言的型別系統的一種擴充套件,以支援建立可以按型別進行引數化的類。可以把型別引數看作是使用引數化型別時指定的型別的一個佔位符,就像方法的形式引數是執行時傳遞的值的佔位符一樣。
可以在集合框架(Collection framework)中看到泛型的動機。例如,Map 類允許您向一個 Map 新增任意類的物件,即使最常見的情況是在給定對映(map)中儲存某個特定型別(比如 String)的物件。
因為 Map.get() 被定義為返回 Object,所以一般必須將 Map.get() 的結果強制型別轉換為期望的型別,如下面的程式碼所示:
Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");
要讓程式透過編譯,必須將 get() 的結果強制型別轉換為 String,並且希望結果真的是一個 String。但是有可能某人已經在該對映中儲存了不是 String 的東西,這樣的話,上面的程式碼將會丟擲 ClassCastException。
理想情況下,您可能會得出這樣一個觀點,即 m 是一個 Map,它將 String 鍵對映到 String 值。這可以讓您消除程式碼中的強制型別轉換,同時獲得一個附加的型別檢查層,該檢查層可以防止有人將錯誤型別的鍵或值儲存在集合中。這就是泛型所做的工作。
2. 泛型的好處
Java 語言中引入泛型是一個較大的功能增強。不僅語言、型別系統和編譯器有了較大的變化,以支援泛型,而且類庫也進行了大翻修,所以許多重要的類,比如集合框架,都已經成為泛型化的了。這帶來了很多好處:
型別安全。 泛型的主要目標是提高 Java 程式的型別安全。透過知道使用泛型定義的變數的型別限制,編譯器可以在一個高得多的程度上驗證型別假設。沒有泛型,這些假設就只存在於程式設計師的頭腦中(或者如果幸運的話,還存在於程式碼註釋中)。
Java 程式中的一種流行技術是定義這樣的集合,即它的元素或鍵是公共型別的,比如“String 列表”或者“String 到 String 的對映”。透過在變數宣告中捕獲這一附加的型別資訊,泛型允許編譯器實施這些附加的型別約束。型別錯誤現在就可以在編譯時被捕獲了,而不是在執行時當作 ClassCastException 展示出來。將型別檢查從執行時挪到編譯時有助於您更容易找到錯誤,並可提高程式的可靠性。
消除強制型別轉換。 泛型的一個附帶好處是,消除原始碼中的許多強制型別轉換。這使得程式碼更加可讀,並且減少了出錯機會。
儘管減少強制型別轉換可以降低使用泛型類的程式碼的羅嗦程度,但是宣告泛型變數會帶來相應的羅嗦。比較下面兩個程式碼例子。
該程式碼不使用泛型:
List li = new ArrayList();
li.put(new Integer(3));
Integer i = (Integer) li.get(0);
該程式碼使用泛型:
Listli = new ArrayList();
li.put(new Integer(3));
Integer i = li.get(0);
在簡單的程式中使用一次泛型變數不會降低羅嗦程度。但是對於多次使用泛型變數的大型程式來說,則可以累積起來降低羅嗦程度。
潛在的效能收益。 泛型為較大的最佳化帶來可能。在泛型的初始實現中,編譯器將強制型別轉換(沒有泛型的話,程式設計師會指定這些強制型別轉換)插入生成的位元組碼中。但是更多型別資訊可用於編譯器這一事實,為未來版本的 JVM 的最佳化帶來可能。
由於泛型的實現方式,支援泛型(幾乎)不需要 JVM 或類檔案更改。所有工作都在編譯器中完成,編譯器生成類似於沒有泛型(和強制型別轉換)時所寫的程式碼,只是更能確保型別安全而已。
3. 泛型用法的例子
泛型的許多最佳例子都來自集合框架,因為泛型讓您在儲存在集合中的元素上指定型別約束。考慮這個使用 Map 類的例子,其中涉及一定程度的最佳化,即 Map.get() 返回的結果將確實是一個 String:
Map m = new HashMap();
m.put("key", "blarg");
String s = (String) m.get("key");
如果有人已經在對映中放置了不是 String 的其他東西,上面的程式碼將會丟擲 ClassCastException。泛型允許您表達這樣的型別約束,即 m 是一個將 String 鍵對映到 String 值的 Map。這可以消除程式碼中的強制型別轉換,同時獲得一個附加的型別檢查層,這個檢查層可以防止有人將錯誤型別的鍵或值儲存在集合中。
下面的程式碼示例展示了 JDK 5.0 中集合框架中的 Map 介面的定義的一部分:
public interface Map{
public void put(K key, V value);
public V get(K key);
}
注意該介面的兩個附加物:
型別引數 K 和 V 在類級別的規格說明,表示在宣告一個 Map 型別的變數時指定的型別的佔位符。
在 get()、put() 和其他方法的方法簽名中使用的 K 和 V。
為了贏得使用泛型的好處,必須在定義或例項化 Map 型別的變數時為 K 和 V 提供具體的值。以一種相對直觀的方式做這件事:
Mapm = new HashMap();
m.put("key", "blarg");
String s = m.get("key");
當使用 Map 的泛型化版本時,您不再需要將 Map.get() 的結果強制型別轉換為 String,因為編譯器知道 get() 將返回一個 String。
在使用泛型的版本中並沒有減少鍵盤錄入;實際上,比使用強制型別轉換的版本需要做更多鍵入。使用泛型只是帶來了附加的型別安全。因為編譯器知道關於您將放進 Map 中的鍵和值的型別的更多資訊,所以型別檢查從執行時挪到了編譯時,這會提高可靠性並加快開發速度。
向後相容
在 Java 語言中引入泛型的一個重要目標就是維護向後相容。儘管 JDK 5.0 的標準類庫中的許多類,比如集合框架,都已經泛型化了,但是使用集合類(比如 HashMap 和 ArrayList)的現有程式碼將繼續不加修改地在 JDK 5.0 中工作。當然,沒有利用泛型的現有程式碼將不會贏得泛型的型別安全好處。
4. 泛型基礎
4.1 型別引數
在定義泛型類或宣告泛型類的變數時,使用尖括號來指定形式型別引數。形式型別引數與實際型別引數之間的關係類似於形式方法引數與實際方法引數之間的關係,只是型別引數表示型別,而不是表示值。
泛型類中的型別引數幾乎可以用於任何可以使用類名的地方。例如,下面是 java.util.Map 介面的定義的摘錄:
public interface Map{
public void put(K key, V value);
public V get(K key);
}
Map 介面是由兩個型別引數化的,這兩個型別是鍵型別 K 和值型別 V。(不使用泛型)將會接受或返回 Object 的方法現在在它們的方法簽名中使用 K 或 V,指示附加的型別約束位於 Map 的規格說明之下。
當宣告或者例項化一個泛型的物件時,必須指定型別引數的值:
Mapmap = new Ha
shMap();
注意,在本例中,必須指定兩次型別引數。一次是在宣告變數 map 的型別時,另一次是在選擇 HashMap 類的引數化以便可以例項化正確型別的一個例項時。
編譯器在遇到一個 Map型別的變數時,知道 K 和 V 現在被繫結為 String,因此它知道在這樣的變數上呼叫 Map.get() 將會得到 String 型別。
除了異常型別、列舉或匿名內部類以外,任何類都可以具有型別引數。
4.2 命名型別引數
推薦的命名約定是使用大寫的單個字母名稱作為型別引數。這與 C++ 約定有所不同(參閱 附錄 A:與 C++ 模板的比較),並反映了大多數泛型類將具有少量型別引數的假定。對於常見的泛型模式,推薦的名稱是:
K —— 鍵,比如對映的鍵。
V —— 值,比如 List 和 Set 的內容,或者 Map 中的值。
E —— 異常類。
T —— 泛型。
4.3 泛型不是協變的
關於泛型的混淆,一個常見的來源就是假設它們像陣列一樣是協變的。其實它們不是協變的。List
不是 List的父型別。
如果 A 擴充套件 B,那麼 A 的陣列也是 B 的陣列,並且完全可以在需要 B[] 的地方使用 A[]:
Integer[] intArray = new Integer[10];
Number[] numberArray = intArray;
上面的程式碼是有效的,因為一個 Integer 是一個 Number,因而一個 Integer 陣列是 一個 Number 陣列。但是對於泛型來說則不然。下面的程式碼是無效的:
ListintList = new ArrayList();
ListnumberList = intList; // invalid
最初,大多數 Java 程式設計師覺得這缺少協變很煩人,或者甚至是“壞的(broken)”,但是之所以這樣有一個很好的原因。如果可以將 List賦給 List,下面的程式碼就會違背泛型應該提供的型別安全:
ListintList = new ArrayList();
ListnumberList = intList; // invalid
numberList.add(new Float(3.1415));
因為 intList 和 numberList 都是有別名的,如果允許的話,上面的程式碼就會讓您將不是 Integers 的東西放進 intList 中。但是,正如下一屏將會看到的,您有一個更加靈活的方式來定義泛型。
4.4 型別萬用字元
假設您具有該方法:
void printList(List l) {
for (Object o : l)
System.out.println(o);
}
上面的程式碼在 JDK 5.0 上編譯透過,但是如果試圖用 List呼叫它,則會得到警告。出現警告是因為,您將泛型(List)傳遞給一個只承諾將它當作 List(所謂的原始型別)的方法,這將破壞使用泛型的型別安全。
如果試圖編寫像下面這樣的方法,那麼將會怎麼樣?
void printList(List
l) {
for (Object o : l)
System.out.println(o);
}
它仍然不會透過編譯,因為一個 List不是 一個 List
(正如前一屏 泛型不是協變的 中所學的)。這才真正煩人 —— 現在您的泛型版本還沒有普通的非泛型版本有用!
解決方案是使用型別萬用字元:
void printList(List l) {
for (Object o : l)
System.out.println(o);
}
上面程式碼中的問號是一個型別萬用字元。它讀作“問號”。List 是任何泛型 List 的父型別,所以您完全可以將 List
、List或 List<List> 傳遞給 printList()。
4.5 型別萬用字元的作用
型別萬用字元中引入了型別萬用字元,這讓您可以宣告 List 型別的變數。您可以對這樣的 List 做什麼呢?非常方便,可以從中檢索元素,但是不能新增元素。原因不是編譯器知道哪些方法修改列表哪些方法不修改列表,而是(大多數)變化的方法比不變化的方法需要更多的型別資訊。下面的程式碼則工作得很好:
Listli = new ArrayList();
li.add(new Integer(42));
List lu = li;
System.out.println(lu.get(0));
為什麼該程式碼能工作呢?對於 lu,編譯器一點都不知道 List 的型別引數的值。但是編譯器比較聰明,它可以做一些型別推理。在本例中,它推斷未知的型別引數必須擴充套件 Object。(這個特定的推理沒有太大的跳躍,但是編譯器可以作出一些非常令人佩服的型別推理,後面就會看到(在底層細節一節中)。所以它讓您呼叫 List.get() 並推斷返回型別為 Object。 另一方面,下面的程式碼不能工作:
Listli = new ArrayList();
li.add(new Integer(42));
List lu = li;
lu.add(new Integer(43)); // error
在本例中,對於 lu,編譯器不能對 List 的型別引數作出足夠嚴密的推理,以確定將 Integer 傳遞給 List.add() 是型別安全的。所以編譯器將不允許您這麼做。
以免您仍然認為編譯器知道哪些方法更改列表的內容哪些不更改列表內容,請注意下面的程式碼將能工作,因為它不依賴於編譯器必須知道關於 lu 的型別引數的任何資訊:
Listli = new ArrayList();
li.add(new Integer(42));
List lu = li;
lu.clear();
4.6 泛型方法
(在 型別引數 一節中)您已經看到,透過在類的定義中新增一個形式型別引數列表,可以將類泛型化。方法也可以被泛型化,不管它們定義在其中的類是不是泛型化的。
泛型類在多個方法簽名間實施型別約束。在 List中,型別引數 V 出現在 get()、add()、contains() 等方法的簽名中。當建立一個 Map型別的變數時,您就在方法之間宣稱一個型別約束。您傳遞給 add() 的值將與 get() 返回的值的型別相同。
類似地,之所以宣告泛型方法,一般是因為您想要在該方法的多個引數之間宣稱一個型別約束。例如,下面程式碼中的 ifThenElse() 方法,根據它的第一個引數的布林值,它將返回第二個或第三個引數:
publicT ifThenElse(boolean b, T first, T second) {
return b ? first : second;
}
注意,您可以呼叫 ifThenElse(),而不用顯式地告訴編譯器,您想要 T 的什麼值。編譯器不必顯式地被告知 T 將具有什麼值;它只知道這些值都必須相同。編譯器允許您呼叫下面的程式碼,因為編譯器可以使用型別推理來推斷出,替代 T 的 String 滿足所有的型別約束: String s = ifThenElse(b, "a", "b");
類似地,您可以呼叫:
Integer i = ifThenElse(b, new Integer(1), new Integer(2));
但是,編譯器不允許下面的程式碼,因為沒有型別會滿足所需的型別約束:
String s = ifThenElse(b, "pi", new Float(3.14));
為什麼您選擇使用泛型方法,而不是將型別 T 新增到類定義呢?(至少)有兩種情況應該這樣做:
當泛型方法是靜態的時,這種情況下不能使用類型別引數。
當 T 上的型別約束對於方法真正是區域性的時,這意味著沒有在相同類的另一個方法簽名中使用相同型別 T 的約束。透過使得泛型方法的型別引數對於方法是區域性的,可以簡化封閉型別的簽名。
4.7 有限制類型
在前一屏 泛型方法 的例子中,型別引數 V 是無約束的或無限制的型別。有時在還沒有完全指定型別引數時,需要對型別引數指定附加的約束。
考慮例子 Matrix 類,它使用型別引數 V,該引數由 Number 類來限制:
public class Matrix{ ... }
編譯器允許您建立 Matrix或 Matrix型別的變數,但是如果您試圖定義
篇二:java泛型基礎知識總結
Java泛型
Java泛型是java1.5中引入的新特性,在此之前,java透過對型別Object的引用來實現引數型別的“任意化”,特點則是需要進行顯示的強制型別轉換。(而這種顯示的`型別轉換可能是無法進行的,是錯誤的)但編譯器無法發現強制型別轉換可能引起的異常,異常只有在執行時才能出現,成為了系統的安全隱患。----------------------------為啥要進入泛型這個概念 泛型的本質是引數化型別,及所操作的資料型別被指定為一個引數,此引數型別可以用在類、介面、和方法的宣告及建立中,分別被稱為泛型類,泛型介面,及泛型方法。 使用注意事項:
泛型的型別引數只能是類型別(包括自定義類),但是不能是簡單型別 泛型型別引數可以是多個
泛型的引數型別還可以是萬用字元型別
沒有泛型的錯誤:
Import java.util.*;
Public class NoGenericTypeDemo{
Public static void main(String[] args)
{
List names=new ArrayList();
Names.add("張桑拿");
Names.add(new Integer(2);
String nameFirst=(String)names.get(0);
String namesecond=(String)names.get(1);//丟擲異常jav.lang.ClassCastException異常,而且編譯時沒有被發現
}
有時候需要使泛型變數能使用任何的型別,此時可以使用萬用字元”?”否則可能需要編寫許多版本的過載函式,使用萬用字元,使方法printLsit()可以接受各種型別的List物件,否則必須使用過載技術,
Public static void printList(Listlist)
{
//輸出集合中的元素
}
篇三:JAVA泛型的簡單例項
簡單普通類
package test7;
import java.util.ArrayList;
class Student
{
int Number;
String Name;
String Cla;
public int GetNumber()
{
return Number;
}
public void SetNumber(int Number)
{
this.Number = Number;
}
public String GetName()
{
return Name;
}
public void SetName(String Name)
{
this.Name = Name;
}
public String GetCla()
{
return Cla;
}
public void SetCla(String Cla)
{
this.Cla = Cla;
}
public Student(){}
public Student(int Number,String Name,String Cla)
{
this.Number = Number;
this.Name = Name;
this.Cla = Cla;
}
}
public class test071 {
public static void main(String[] args) {
System.out.println("設計者:");
Student s1 = new Student(123, "張三", "11計科");
Student s2 = new Student(124, "李四", "11計科");
Student s3 = new Student(125, "王五", "11計科");
Student dujingjing = new Student(20110105,"杜","11計科");
ArrayList AL = new ArrayList();
AL.add(s1);
AL.add(s2);
AL.add(s3);
AL.add(dujingjing);
for(int i = 0;i<AL.size();i++)
{
Student s = (Student)AL.get(i);
System.out.println("學號:" +s.Number + " 姓名:" +s.Name+ " 班級:" +s.Cla);
}
}
}
簡單泛型例項
java中泛型定義
Java的泛型類就是一個用型別作為引數的類,即帶有引數化型別的類。就像我們定義類的成員方法一樣。大家很熟悉Java的成員方法形式是method(String str,int i),方法中引數str、i的值是可變的。而泛型也是一樣的:class泛型類類名,這裡的K和V就像方法中的引數str和i,也是可變的。
Class UseT{
Private T x;
Public SetX(T x){````````}
}
package test7;
泛型類:L2
class L2
{
private T obj;
public L2(T obj)
{
this.obj = obj;
}
public T getobj()
{
return this.obj;
}
public void setobj(T obj)
{
this.obj = obj;
}
public void showobj(T obj)
{
System.out.println("資料為:" + this.obj); }
}
主類:
public class test072 {
public static void main(String[] args) {
System.out.println("設計者:");
L2name = new L2("汽車"); name.showobj(name.getobj());
L2data = new L2(12); data.showobj(data.getobj());
}
}
簡單集合類
篇四:java泛型總結
泛型總結篇:
1)泛型引數只能是類型別
例如:List// 報錯
List// 正確
2)泛型的型別引數可以有多個!
例如:Listlist = new
ArrayList();
3)泛型的引數型別可以使用extends,習慣稱“有界型別”,
例如:List,person為list的上界
4)泛型可以使用萬用字元型別!“?” 相當於“Object”型別,(注意不可逆) 例如:List //定義成這樣可以新增Object型別到List裡面去 List
; //定義成這樣不可以新增String型別到List裡面去 List; // 這樣就可以互等了!這樣還可以設定泛型的上限
5)帶泛型的類,構造方法寫法不變,其後不可以加泛型!
例如:class Student{
public Student(){} // 構造方法這樣寫就錯了
}
6)List不是 List
的子類!,不可以把前者看成後者的子類,所以不
可以把前者的例項賦給後者
例如: ListSlist = new ArrayList();
Slist.add(new String("abc"));
List
Olist = new ArrayList
();
Olist.add("abc");
Olist = Slist; // 報錯!
7)帶不同泛型引數的例項可以共享類的靜態方法和靜態變數,所以靜態方法和靜態變數
申明的時候不可以使用型別行參
例如:class Cup{
static T info; // 報錯!
public static setInfo(T info){}; // 報錯!
}
8)帶不同泛型引數的類是共享一個位元組碼檔案的!反編譯過後泛型引數就被擦除了
例如:ListSlist = new ArrayList();
Slist.add(new String("aaa"));
ListIlist = new ArrayList();
Ilist.add(new Integer(100));
System.out.println(Slist.getClass()==Ilist.getClass()); 結果為true;
9)當使用定義了泛型引數的介面 和 父類的時候!就不能在帶引數了 例如:class Sub extends Father{} // 錯誤
10)
class T{}
public class typeTest extends T{}//報錯
class T{}
public class typeTest extends T{} // 正確 可使用String等基本封裝型別
class T{}
class Student{}
public class typeTest extends T{} // 這樣也正確
11) 泛型方法 ,泛型方法的引數的作用域僅在本方法,要和方法帶泛型區分開! Staticvoid test(ListS_list){} // 泛型引數要放在返回型別前
12)帶有泛型的程式碼轉換成沒有泛型的程式碼由javac完成,虛擬機器不處理這些事情!
這種技術叫做 “擦除”;
例如:class Food{
T size;
public Food(T size){} //注意構造方法不可以帶泛型引數!
public void setSize(){ this.size = size; }
public T getSize(){ return this.size;}
}
public class test{
public static void main(String arg[]){
Fooda = new Food(6);
Ingeger as = a.getSize(); // 返回的是Integer的型別 Food b = a; //把a物件賦給Food變數;泛型引數型別會丟失 即擦除;
Number size1 = b.getSize(); // b只知道size的型別是Number // Integer in = b.getSize(); 這樣是編譯錯誤的!
} }
篇五:Java泛型簡明教程
導讀:本文是從《Java Generics Quick Tutorial》這篇文章翻譯而來,譯文來自外刊IT評論《Java泛型簡明教程》。內容如下:
泛型是Java SE 5.0中引入的一項特徵,自從這項語言特徵出現多年來,我相信,幾乎所有的Java程式設計師不僅聽說過,而且使用過它。關於Java泛型的教程,免費的,不免費的,有很多。我遇到的最好的教材有:
The Java Tutorial
Java Generics and Collections, by Maurice Naftalin and Philip Wadler
Effective Java中文版(第2版), by Joshua Bloch.
儘管有這麼多豐富的資料,有時我感覺,有很多的程式設計師仍然不太明白Java泛型的功能和意義。這就是為什麼我想使用一種最簡單的形式來總結一下程式設計師需要知道的關於Java泛型的最基本的知識。
Java泛型由來的動機
理解Java泛型最簡單的方法是把它看成一種便捷語法,能節省你某些Java型別轉換(casting)上的操作:
1. Listbox = ...;
2. Apple apple = box.get(0);
上面的程式碼自身已表達的很清楚:box是一個裝有Apple物件的List。get方法返回一個Apple物件例項,這個過程不需要進行型別轉換。沒有泛型,上面的程式碼需要寫成這樣:
1. List box = ...;
2. Apple apple = (Apple) box.get(0);
很明顯,泛型的主要好處就是讓編譯器保留引數的型別資訊,執行型別檢查,執行型別轉換操作:編譯器保證了這些型別轉換的絕對無誤。
相對於依賴程式設計師來記住物件型別、執行型別轉換——這會導致程式執行時的失敗,很難除錯和解決,而編譯器能夠幫助程式設計師在編譯時強制進行大量的型別檢查,發現其中的錯誤。 泛型的構成
由泛型的構成引出了一個型別變數的概念。根據Java語言規範,型別變數是一種沒有限制的標誌符,產生於以下幾種情況:
泛型類宣告
泛型介面宣告
泛型方法宣告
泛型構造器(constructor)宣告
泛型類和介面
如果一個類或介面上有一個或多個型別變數,那它就是泛型。型別變數由尖括號界定,放在類或介面名的後面:
1. public interface Listextends Collection{
2.
3. ...
4. }
簡單的說,型別變數扮演的角色就如同一個引數,它提供給編譯器用來型別檢查的資訊。 Java類庫裡的很多類,例如整個Collection框架都做了泛型化的修改。例如,我們在上面的第一段程式碼裡用到的List介面就是一個泛型類。在那段程式碼裡,box是一個List物件,它是一個帶有一個Apple型別變數的List介面的類實現的例項。編譯器使用這個型別變數引數在get方法被呼叫、返回一個Apple物件時自動對其進行型別轉換。 實際上,這新出現的泛型標記,或者說這個List接口裡的get方法是這樣的:
1. T get(int index);
get方法實際返回的是一個型別為T的物件,T是在List宣告中的型別變數。 泛型方法和構造器(Constructor)
非常的相似,如果方法和構造器上聲明瞭一個或多個型別變數,它們也可以泛型化。
1. public staticT getFirst(Listlist)
這個方法將會接受一個List型別的引數,返回一個T型別的物件。
例子
你既可以使用Java類庫裡提供的泛型類,也可以使用自己的泛型類。
型別安全的寫入資料…
下面的這段程式碼是個例子,我們建立了一個List例項,然後裝入一些資料:
1. Liststr = new ArrayList();
2.
3. str.add("Hello ");
4.
5. str.add("World.");
如果我們試圖在List裝入另外一種物件,編譯器就會提示錯誤:
1. str.add(1); //不能編譯
型別安全的讀取資料…
當我們在使用List物件時,它總能保證我們得到的是一個String物件:
1. String myString = str.get(0);
遍歷
類庫中的很多類,諸如Iterator,功能都有所增強,被泛型化。List接口裡的 iterator()方法現在返回的是Iterator,由它的T next()方法返回的物件不需要再進行型別轉換,你直接得到正確的型別。
1. for (Iteratoriter = str.iterator(); iter.hasNext();){
2.
3. String s = iter.next();
4.
5. System.out.print(s);
6.
7. }
使用foreach
“for each”語法同樣受益於泛型。前面的程式碼可以寫出這樣:
1. for (String s: str){
2.
3. System.out.print(s);
4.
5. }
這樣既容易閱讀也容易維護。
自動封裝(Autoboxing)和自動拆封(Autounboxing)
在使用Java泛型時,autoboxing/autounboxing這兩個特徵會被自動的用到,就像下面的這段程式碼:
1. Listints = new ArrayList();
2.
3. ints.add(0);
4.
5. ints.add(1);
6.
7.
8.
9.
10.int sum = 0;
11.
12.for (int i : ints){
13.
14.sum += i;
15.
16.}
然而,你要明白的一點是,封裝和解封會帶來效能上的損失,所有,通用要謹慎的使用。 子型別
在Java中,跟其它具有面向物件型別的語言一樣,型別的層級可以被設計成這樣:
在Java中,型別T的子型別既可以是型別T的一個擴充套件,也可以是型別T的一個直接或非直接實現(如果T是一個介面的話)。因為“成為某型別的子型別”是一個具有傳遞性質的關係,如果型別A是B的一個子型別,B是C的子型別,那麼A也是C的子型別。在上面的圖中: FujiApple(富士蘋果)是Apple的子型別
Apple是Fruit(水果)的子型別
FujiApple(富士蘋果)是Fruit(水果)的子型別
所有Java型別都是Object型別的子型別。
B型別的任何一個子型別A都可以被賦給一個型別B的宣告:
1. Apple a = ...;
2. Fruit f = a;
泛型型別的子型別
如果一個Apple物件的例項可以被賦給一個Fruit物件的宣告,就像上面看到的,那麼,List和 a List之間又是個什麼關係呢?更通用些,如果型別A是型別B的子型別,那C 和 C之間是什麼關係?
答案會出乎你的意料:沒有任何關係。用更通俗的話,泛型型別跟其是否子型別沒有任何關係。