Java從1.5以後支持泛型,泛型的本質是參數化類型,也就是說所操做的數據類型被指定爲一個參數。這種參數類型能夠用在類、接口和方法的建立中,分別稱爲泛型類、泛型接口、泛型方法。javascript
入不支持泛型,則表現爲支持Object,不是特定的泛型。css
泛型是對 Java 語言的類型系統的一種擴展,以支持建立能夠按類型進行參數化的類。能夠把類型參數看做是使用參數化類型時指定的類型的一個佔位符,就像方法的形式參數是運行時傳遞的值的佔位符同樣。java
能夠在集合框架中看到泛型的動機。例如,List類容許您向一個 List添加任意類的對象,即便最多見的狀況List.add()。
由於 list.get() 被定義爲返回 Object,因此通常必須將 list.get() 的結果強制類型轉換爲指望的類型,以下面的代碼所示:
List list = new ArrayList();
list .add("obj");
String s = (String) list.get(0);
要讓程序經過編譯,必須將 get() 的結果強制類型轉換爲 String,而且但願結果然的是一個 String。可是有可能某人已經在該映射中保存了不是 String 的東西,這樣的話,上面的代碼將會拋出 ClassCastException。
理想狀況下,您可能會得出這樣一個觀點,即 list 是一個 List,它將 String 鍵映射到 String 值。android
泛型能夠消除代碼中的強制類型轉換,同時得到一個附加的類型檢查層,該檢查層能夠防止有人將錯誤類型的鍵或值保存在集合中。這就是泛型所作的工做。程序員
泛型的好處數組
Java 語言中引入泛型是一個較大的功能加強。不只語言、類型系統和編譯器有了較大的變化,以支持泛型,並且類庫也進行了大翻修,因此許多重要的類,好比集合框架,都已經成爲泛型化的了。安全
這帶來了不少好處:
1,類型安全。 泛型的主要目標是提升 Java 程序的類型安全。經過知道使用泛型定義的變量的類型限制,編譯器能夠在一個高得多的程度上驗證類型假設。ruby
沒有泛型,這些假設就只存在於程序員的頭腦中(或者若是幸運的話,還存在於代碼註釋中)。 框架
2,消除強制類型轉換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉換。這使得代碼更加可讀,而且減小了出錯機會。性能
3,潛在的性能收益。 泛型爲較大的優化帶來可能。在泛型的初始實現中,編譯器將強制類型轉換(沒有泛型的話,程序員會指定這些強制類型轉換)插入生成的字節碼中。
可是更多類型信息可用於編譯器這一事實,爲將來版本的 JVM 的優化帶來可能。因爲泛型的實現方式,支持泛型(幾乎)不須要 JVM 或類文件更改。
全部工做都在編譯器中完成,編譯器生成相似於沒有泛型(和強制類型轉換)時所寫的代碼,只是更能確保類型安全而已。
Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,而且全部的強制轉換都是自動和隱式的,提升代碼的重用率。
泛型在使用中還有一些規則和限制:
一、泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
二、同一種泛型能夠對應多個版本(由於參數類型是不肯定的),不一樣版本的泛型類實例是不兼容的。
三、泛型的類型參數能夠有多個。
四、泛型的參數類型可使用extends語句,例如<T extends superclass>。習慣上成爲「有界類型」。
五、泛型的參數類型還能夠是通配符類型。例如Class<?> classType = Class.forName(Java.lang.String);
泛 型還有接口、方法等等,內容不少,須要花費一番功夫才能理解掌握並熟練應用。在此給出我曾經瞭解泛型時候寫出的兩個例子(根據看的印象寫的),實現一樣的 功能,一個使用了泛型,一個沒有使用,經過對比,能夠很快學會泛型的應用,學會這個基本上學會了泛型70%的內容。
泛型的使用場景
在開發中對象的引用傳遞是最多見的,可是在泛型操做中,進行引用傳遞的時候泛型必須匹配才能夠傳遞,不然沒法傳遞。
class Info<T>{
private T var ; // 定義泛型變量
public void setVar(T var){
this.var = var ;
}
public T getVar(){
return this.var ;
}
public String toString(){
// 直接打印
return this.var.toString() ;
} };
public class GenericsDemo14{
public static void main(String args[]){ Info<String> i = new Info<String>() ; // 使用String爲泛型類型 i.setVar("MLDN") ; // 設置內容 fun(i) ; } public static void fun(Info<?> temp){ // 能夠接收任意的泛型對象 System.out.println("內容:" + temp) ; } };
使用?能夠接受任意類型的數據,卻沒法進行修改,?w爲通配符。
class Info<T> { private T var; // 定義泛型變量 public T getVar() { return var; } public void setVar(T var) { this.var = var; } public String toString(){ // 直接打印 return var.toString(); } } public class GenericsDemo17 { /** * @param args */ public static void main(String[] args) { // TODO Auto-generated method stub Info<Integer> info1 = new Info<Integer>(); // 聲明Integer的泛型對象 Info<Float> info2 = new Info<Float>(); // 聲明Float的泛型對象 Info<String> info3 = new Info<String>(); info1.setVar(30); // 設置整數,自動裝箱 info2.setVar(30.1F); // 設置小數,自動裝箱 info3.setVar("俺是字符串,不能被受限的FUN組裝"); fun(info1); fun(info2); // fun(info3); //受限了,不能調用這個 } /** * 能夠接收任意的泛型對象(// 只能接收Number及其Number的子類) * @param temp */ public static void fun(Info<? extends Number> temp){ // 只能接收String或Object類型的泛型 //public static void fun(Info<? super String> temp){ System.out.println("內容:"+temp); } }
不只僅在使用過程當中,也能夠在定義類的時候指定泛型上限:
class Info<T extends Number>{ // 此處泛型只能是數字類型 private T var ; // 定義泛型變量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo19{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; // 聲明Integer的泛型對象 } };
若是設置成Stirng類型就會出現錯誤:
GenericsDemo20.java:15: 類型參數 java.lang.String 不在其限制範圍以內 Info<String> i1 = new Info<String>() ; // 聲明Integer的 泛型對象
String 不是Number的子類,最高不能超過Number的子類。
泛型適用於本類以及父類類型上的時候,必須使用泛型下限。
以下只能接受String以及String的父類。最低不能接受Stirng類及其父類之外的類。
class Info<T>{ private T var ; // 定義泛型變量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo21{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; // 聲明String的泛型對象 Info<Object> i2 = new Info<Object>() ; // 聲明Object的泛型對象 i1.setVar("hello") ; i2.setVar(new Object()) ; fun(i1) ; fun(i2) ; } public static void fun(Info<? super String> temp){ // 只能接收String或Object類型的泛型 System.out.print(temp + "、") ; } };
注意:子類沒法使用父類的泛型類型進行接受。
class Info<T>{ private T var ; // 定義泛型變量 public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } public String toString(){ // 直接打印 return this.var.toString() ; } }; public class GenericsDemo23{ public static void main(String args[]){ Info<String> i1 = new Info<String>() ; // 泛型類型爲String Info<Object> i2 = null ; i2 = i1 ; } };
就會爆以下錯誤:
GenericsDemo23.java:17: 不兼容的類型 找到: Info<java.lang.String> 須要: Info<java.lang.Object> i2 = i1 ; ^
在jdk1.5之後,不只僅能夠聲明泛型類,也能夠聲明泛型接口,泛型接口很相似泛型類:
訪問權限 +interface +接口名稱 + <泛型標示>{}
1:
interface Info<T>{ // 在接口上定義泛型 public T getVar() ; // 定義抽象方法,抽象方法的返回值就是泛型類型 } class InfoImpl implements Info<String>{ // 定義泛型接口的子類 private String var ; // 定義屬性 public InfoImpl(String var){ // 經過構造方法設置屬性內容 this.setVar(var) ; } public void setVar(String var){ this.var = var ; } public String getVar(){ return this.var ; } }; public class GenericsDemo{ public static void main(String arsg[]){ Info i = null; // 聲明接口對象 i = new InfoImpl("soyoungboy") ; // 經過子類實例化對象 System.out.println("內容:" + i.getVar()) ; } };
2:
interface Info<T>{ // 在接口上定義泛型 public T getVar() ; // 定義抽象方法,抽象方法的返回值就是泛型類型 } class InfoImpl<T> implements Info<T>{ // 定義泛型接口的子類 private T var ; // 定義屬性 public InfoImpl(T var){ // 經過構造方法設置屬性內容 this.setVar(var) ; } public void setVar(T var){ this.var = var ; } public T getVar(){ return this.var ; } }; public class GenericsDemo{ public static void main(String arsg[]){ Info<String> i = null; // 聲明接口對象 i = new InfoImpl<String>("soyoungboy") ; // 經過子類實例化對象 System.out.println("內容:" + i.getVar()) ; } };
泛型方法定義:
訪問權限 +<泛型標示>+泛型標示 方法名稱(泛型標示 參數名稱)
class Demo{ public <T> T fun(T t){ // 能夠接收任意類型的數據 return t ; // 直接把參數返回 } }; public class GenericsDemo{ public static void main(String args[]){ Demo d = new Demo() ; // 實例化Demo對象 String str = d.fun("soyoungboy") ; // 傳遞字符串 int i = d.fun(30) ; // 傳遞數字,自動裝箱 System.out.println(str) ; // 輸出內容 System.out.println(i) ; // 輸出內容 } };
class Info<T extends Number>{ // 指定上限,只能是數字類型 private T var ; // 此類型由外部決定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆寫Object類中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo27{ public static void main(String args[]){ Info<Integer> i = fun(30) ; System.out.println(i.getVar()) ; } public static <T extends Number> Info<T> fun(T param){ Info<T> temp = new Info<T>() ; // 根據傳入的數據類型實例化Info temp.setVar(param) ; // 將傳遞的內容設置到Info對象的var屬性之中 return temp ; // 返回實例化對象 } };
class Info<T>{ // 指定上限,只能是數字類型 private T var ; // 此類型由外部決定 public T getVar(){ return this.var ; } public void setVar(T var){ this.var = var ; } public String toString(){ // 覆寫Object類中的toString()方法 return this.var.toString() ; } }; public class GenericsDemo{ public static void main(String args[]){ Info<Integer> i1 = new Info<Integer>() ; Info<String> i2 = new Info<String>() ; i1.setVar(30) ; // 設置內容 i2.setVar("aoyoungboy") ; // 設置內容 add(i1,i2) ; } public static <T> void add(Info<T> i1,Info<T> i2){ System.out.println(i1.getVar() + " " + i2.getVar()) ; } };
就會產生錯誤:
泛型】_泛型的其餘應用\代碼>javac GenericsDemo.java GenericsDemo29.java:19: 沒法將 GenericsDemo 中的 <T>add(Info<T>,Info<T>) 應用 於 (Info<java.lang.Integer>,Info<java.lang.String>) add(i1,i2) ; ^
使用泛型方法的時候,也能夠傳遞或者返回一個泛型數組:
public class GenericsDemo{ public static void main(String args[]){ Integer i[] = fun1(1,2,3,4,5,6) ; // 返回泛型數組 fun2(i) ; } public static <T> T[] fun1(T...arg){ // 接收可變參數 return arg ; // 返回泛型數組 } public static <T> void fun2(T param[]){ // 輸出 System.out.print("接收泛型數組:") ; for(T t:param){ System.out.print(t + "、") ; } } };
class Info<T,V>{ // 接收兩個泛型類型 private T var ; private V value ; public Info(T var,V value){ this.setVar(var) ; this.setValue(value) ; } public void setVar(T var){ this.var = var ; } public void setValue(V value){ this.value = value ; } public T getVar(){ return this.var ; } public V getValue(){ return this.value ; } }; class Demo<S>{ private S info ; public Demo(S info){ this.setInfo(info) ; } public void setInfo(S info){ this.info = info ; } public S getInfo(){ return this.info ; } }; public class GenericsDemo{ public static void main(String args[]){ Demo<Info<String,Integer>> d = null ; // 將Info做爲Demo的泛型類型 Info<String,Integer> i = null ; // Info指定兩個泛型類型 i = new Info<String,Integer>("李興華",30) ; // 實例化Info對象 d = new Demo<Info<String,Integer>>(i) ; // 在Demo類中設置Info類的對象 System.out.println("內容一:" + d.getInfo().getVar()) ; System.out.println("內容二:" + d.getInfo().getValue()) ; } };