泛型是Java SE 1.5的新特性,泛型的本質是參數化類型 ,也就是說所操作的資料型態被指定為一個參數。
在Java SE 1.5之前,沒有泛型的情況的下,透過對型別Object的引用來實現參數的“任意化”,“任意化”帶來的缺點是要做顯式的強制類型轉換,而這種轉換是要求開發者對實際參數類型可以預知的情況下進行的。 對於強制類型轉換錯誤的情況,編譯器可能不提示錯誤,在運行的時候才出現異常,這是一個安全隱患。
泛型的好處是在編譯的時候檢查型別安全,並且所有的強制轉換都是自動和隱式的,以提高程式碼的重用率。
首先我們來看一個案例,向一個ArrayList新增字串,「不小心」新增了整數,如下面程式碼,
並沒有錯誤:
#但執行時,會報錯:「java.lang.classCastException」
因為ArrayList中維護的是一個Object數組, private transient Object[] elementData;
, 使用get()傳回的是一個Object對象, 需要強制轉換,但中間混雜一個Integer數值, 導致強制轉換失敗。這個錯誤就是由於Object的任意化所導致的。
如果能在編譯階段就發現資料型別有錯, 那麼就很方便,泛型就滿足了這個要求:我將這個程式修改一下,ArrayList使用泛型:會發現編譯階段就報錯了.
#不使用泛型:
package com.chb.fanxing;public class NoGen { private Object ob; public NoGen(Object ob) { this.ob = ob; } getter setter... private void showType() { System.out.println("数据的实际类型是:" + ob.getClass().getName()); } public static void main(String[] args) { NoGen ngInt = new NoGen(88); ngInt.showType(); int i = (int)ngInt.getOb(); System.out.println("value = " + i); System.out.println("---------------"); NoGen ngStr = new NoGen("88"); ngStr.showType(); String str = (String)ngStr.getOb(); System.out.println("value = " + str); } }
使用泛型:
package com.chb.fanxing;public class Gen<T> { private T ob; public Gen(T ob) { this.ob = ob; } getter setter... private void showType() { System.out.println("T的实际类型:"+ob.getClass().getName()); } public static void main(String[] args) { //定义一个Integer版本 Gen<Integer> genInt = new Gen<Integer>(88); genInt.showType(); int i = genInt.getOb();//此处不用强制转换 System.out.println("value = " + i); System.out.println("----------------------"); Gen<String> genStr = new Gen<String>("88"); genStr.showType(); String str = genStr.getOb(); System.out.println("value = "+str); } }
兩個例子的運行結果是一致的
数据的实际类型是:java.lang.Integervalue = 88 ---------------数据的实际类型是:java.lang.String value = 88
對比兩個例子會發現:
使用泛型,強制轉換時自動進行的:
int i = genInt.getOb();//此处不用强制转换
而不使用泛型,必須要進行手動強制轉換
int i = (int)ngInt.getOb();
class StringDemo { private String s; public StringDemo (String s) { this.s = s; } setter geter.... } class DoubleDemo{ private Double d; public DoubleDemo(Double d) { this.d = d; } setter getter... }
仔細觀察兩個類別功能基本上一致,只是資料型別不一樣,考慮到重構,因為Object是所有類別的基類,所以可以使用Object作為成員變量,這樣程式碼就可以通用了。重構程式碼如下:
class ObjectDemo{ private Object ob; public ObjectDemo(Object ob){ this.ob = ob; } setter getter... }
ObjectDemo測試:
public static void ObjectDemoTest(){ ObjectDemo strOD = new ObjectDemo("123"); ObjectDemo dOD = new ObjectDemo(new Double(23)); ObjectDemo od = new ObjectDemo(new Object()); System.out.println((String)strOD.getOb()); System.out.println((Double)dOD.getOb()); System.out.println(od.getOb()); }
執行結果:
##發現上面的ObjectDemoTest()
中必須要使用強制轉換,這比較麻煩,我們還必須事先知道要轉換的資料型別,才能進行正確的轉換,否則,會出現錯誤, 業務編譯時沒有問題,但是一運行,會出現」classCastException」。所以我們需要不用自己進行強制轉換,這是泛型就特別重要。
class GenDemo<T>{ private T t; public GenDemo(T t) { this.t = t; } public void setT(T t) { this.t = t; } public T getT() { return t; } }
測試:省去了手動進行強制轉換
public static void GenTest() { GenDemo<String> strOD = new GenDemo<String>("123"); GenDemo<Double> dOD = new GenDemo<Double>(new Double(23)); GenDemo<Object> od = new GenDemo<Object>(new Object()); System.out.println(strOD.getT()); System.out.println(dOD.getT()); System.out.println(od.getT()); }
使用表示一個類型持有者名稱, 相當於一個形參,資料的型別是有實際傳入的資料的型別決定,然後T作為成員、參數、方法的回傳值的型別。
T只是一個名字,可以隨意取的。
class GenDemo , T沒有進行任何限制, 實際相當於 Object,
等同於 class GenDemo。
與Object相比,使用泛型所定義的類,在定義和聲明,可以使用來製定真實的資料類型,如:
dOD = new GenDemo
限制泛型
多重介面限制
通配符泛型
泛型是Java SE 1.5的新特性,泛型的本质是参数化类型,也就是说所操作的数据类型被指定为一个参数。
在Java SE 1.5之前,没有泛型的情况的下,通过对类型Object的引用来实现参数的“任意化”,“任意化”带来的缺点是要做显式的强制类型转换,而这种转换是要求开发者对实际参数类型可以预知的情况下进行的。对于强制类型转换错误的情况,编译器可能不提示错误,在运行的时候才出现异常,这是一个安全隐患。
泛型的好处是在编译的时候检查类型安全,并且所有的强制转换都是自动和隐式的,以提高代码的重用率。
首先我们看一个案例,向一个ArrayList中添加字符串,“不小心”添加了整数,如下面代码,
并没有错误:
但是执行时,会报错:“java.lang.classCastException”
因为ArrayList中维护的是一个Object数组, private transient Object[] elementData;
, 使用get()返回的是一个Object对象, 需要强制转换,但是中间混杂一个Integer数值, 导致强制转换失败。这个错误就是由于Object的任意化导致的。
如果能在编译阶段就发现数据类型有错, 那么就很方便,泛型就满足了这个要求:我将这个程序修改一下,ArrayList使用泛型:会发现编译阶段就报错了.
不使用泛型:
package com.chb.fanxing;public class NoGen { private Object ob; public NoGen(Object ob) { this.ob = ob; } getter setter... private void showType() { System.out.println("数据的实际类型是:" + ob.getClass().getName()); } public static void main(String[] args) { NoGen ngInt = new NoGen(88); ngInt.showType(); int i = (int)ngInt.getOb(); System.out.println("value = " + i); System.out.println("---------------"); NoGen ngStr = new NoGen("88"); ngStr.showType(); String str = (String)ngStr.getOb(); System.out.println("value = " + str); } }
使用泛型:
package com.chb.fanxing;public class Gen<T> { private T ob; public Gen(T ob) { this.ob = ob; } getter setter... private void showType() { System.out.println("T的实际类型:"+ob.getClass().getName()); } public static void main(String[] args) { //定义一个Integer版本 Gen<Integer> genInt = new Gen<Integer>(88); genInt.showType(); int i = genInt.getOb();//此处不用强制转换 System.out.println("value = " + i); System.out.println("----------------------"); Gen<String> genStr = new Gen<String>("88"); genStr.showType(); String str = genStr.getOb(); System.out.println("value = "+str); } }
两个例子的运行结果是一致的
数据的实际类型是:java.lang.Integervalue = 88 ---------------数据的实际类型是:java.lang.String value = 88
对比两个例子会发现:
使用泛型,强制转换时自动进行的:
int i = genInt.getOb();//此处不用强制转换
而不使用泛型,必须要进行手动强制转化
int i = (int)ngInt.getOb();
class StringDemo { private String s; public StringDemo (String s) { this.s = s; } setter geter.... } class DoubleDemo{ private Double d; public DoubleDemo(Double d) { this.d = d; } setter getter... }
仔细观察两个类功能基本一致,只是数据类型不一样,考虑到重构,因为Object是所有类的基类,所以可以使用Object作为成员变量,这样代码就可以通用了。重构代码如下:
class ObjectDemo{ private Object ob; public ObjectDemo(Object ob){ this.ob = ob; } setter getter... }
ObjectDemo测试:
public static void ObjectDemoTest(){ ObjectDemo strOD = new ObjectDemo("123"); ObjectDemo dOD = new ObjectDemo(new Double(23)); ObjectDemo od = new ObjectDemo(new Object()); System.out.println((String)strOD.getOb()); System.out.println((Double)dOD.getOb()); System.out.println(od.getOb()); }
运行结果:
发现上面的ObjectDemoTest()
中必须要使用强制转换,这比较麻烦,我们还必须事先知道要转换的数据类型,才能进行正确的转换,否则,会出现错误, 业务编译时没有问题,但是一运行,会出现”classCastException”。所以我们需要不用自己进行强制转换,这是泛型就尤为重要。
class GenDemo<T>{ private T t; public GenDemo(T t) { this.t = t; } public void setT(T t) { this.t = t; } public T getT() { return t; } }
测试:省去了手动进行强制转换
public static void GenTest() { GenDemo<String> strOD = new GenDemo<String>("123"); GenDemo<Double> dOD = new GenDemo<Double>(new Double(23)); GenDemo<Object> od = new GenDemo<Object>(new Object()); System.out.println(strOD.getT()); System.out.println(dOD.getT()); System.out.println(od.getT()); }
使用表示一个类型持有者名称, 相当于一个形参,数据的类型是有实际传入的数据的类型决定,然后T作为成员、参数、方法的返回值的类型。
T仅仅是一个名字,可以随意取的。
class GenDemo , T没有进行任何限制, 实际相当于 Object,
等同于 class GenDemo。
与Object相比,使用泛型所定义的类,在定义和声明,可以使用来制定真实的数据类型,如:
GenDemo
也可以不指定,那么就需要进行强制转换。
以上就是java之泛型的内容,更多相关内容请关注PHP中文网(www.php.cn)!