在學(xué)習(xí)泛型之前我們先回顧下JAVA的數(shù)據(jù)類型以及涉及到的一些概念。
Java數(shù)據(jù)類型
Java的兩大數(shù)據(jù)類型分為基礎(chǔ)類型和引用類型。基本類型的數(shù)值不是對象,不能調(diào)用對象的toString()、hashCode()、getClass()、equals()等方法。

自動裝箱
把基本類型用它們對應(yīng)的引用類型包裝起來,使它們具有對象的特質(zhì),可以調(diào)用toString()、hashCode()、getClass()、equals()等方法。
例如:
//自動裝箱
Integer i=1;
而實際上編譯器會調(diào)用static Integer valueOf(int i)這個方法,返回一個表示指定int值的Integer對象。Integer i=1; ->. Integer i=Integer.valueOf(1);
拆箱
跟自動裝箱的方向相反,將引用類型轉(zhuǎn)換為基本類型。
//拆箱
int i = new Integer(1);
自動裝箱和拆箱是由編譯器來完成的,編譯器會在編譯期根據(jù)語法決定是否進(jìn)行裝箱和拆箱動作。
假如我們定義一個類來表示坐標(biāo),要求類中基礎(chǔ)類型可以為整數(shù) 、小數(shù)、字符串,例如:
Object x=116,y=54;
Object x=116.92,y=54.31;
Object x="經(jīng)度116.92",y="緯度54.31";
我們知道,基本數(shù)據(jù)類型可以自動裝箱,被轉(zhuǎn)換成對應(yīng)的包裝類。Object 是所有類的祖先類,任何一個類的實例都可以向上轉(zhuǎn)型為 Object 類型,例如:
int -> Integer -> Object
double -> Double -> Object
String -> Object
泛型的使用

如果要取出坐標(biāo)值就需要向下轉(zhuǎn)型,向下轉(zhuǎn)型存在著風(fēng)險,而且編譯期間不容易發(fā)現(xiàn),只有在運(yùn)行期間才會拋出異常,所以要盡量避免使用向下轉(zhuǎn)型。例如下面的實例:
public class Test {
public static void main(String[] args){
Point point = new Point();
//int -> Integer -> Object
point.setX(116);
point.setY(54);
//向下轉(zhuǎn)型
int x = (Integer) point.getX();
int y = (Integer) point.getY();
System.out.println("Point :x="+x+" y="+y);
//double -> Double -> Object
point.setX(116.92);
point.setY("緯度54.32");
//向下轉(zhuǎn)型
Double x1 = (Double) point.getX();
//會拋出ClassCastException異常
Double y1 = (Double) point.getY();
System.out.println("Point :x1="+x1+" y1="+y1);
}
}
class Point{
Object x = null;
Object y = null;
public Object getX() {
return x;
}
public void setX(Object x) {
this.x = x;
}
public Object getY() {
return y;
}
public void setY(Object y) {
this.y = y;
}
}
那么Java中如何避免這樣的情況發(fā)生呢?
Java中泛型出現(xiàn)就是解決出現(xiàn)這樣的問題,所謂的“泛型”就是任意的數(shù)據(jù)類型。以下代碼將利用泛型解決上面的問題。
public class Test {
public static void main(String[] args){
//實例化泛型
Point<Integer,Integer> point = new Point<Integer,Integer>();
point.setX(116);
point.setY(54);
int x = point.getX();
int y = point.getY();
System.out.println("Point :x="+x+" y="+y);
Point<Double,String> point1 = new Point<Double,String>();
point1.setX(116.92);
point1.setY("緯度54.32");
Double x1 = point1.getX();
String y1 = point1.getY();
System.out.println("Point :x1="+x1+" y1="+y1);
}
}
//定義泛型類
class Point<T1,T2>{
T1 x = null;
T2 y = null;
public T2 getY() {
return y;
}
public void setY(T2 y) {
this.y = y;
}
public T1 getX() {
return x;
}
public void setX(T1 x) {
this.x = x;
}
}
實例中的T1和T2叫類型參數(shù),類型參數(shù)是用來表示自定義標(biāo)識符,用來傳遞數(shù)據(jù)的類型。Java中傳值參數(shù)用小括號包圍,泛型參數(shù)用尖括號包圍,多個參數(shù)用逗號間隔,例如:
<T>或<T,E>
類型參數(shù)需要在類名后面給出。一旦給出了類型參數(shù),就可以在類中使用了。類型參數(shù)必須是一個合法的標(biāo)識符,習(xí)慣上使用單個大寫字母,通常情況下,K 表示鍵,V 表示值,E 表示異常或錯誤,T 表示一般意義上的數(shù)據(jù)類型。
泛型類在實例化時必須指出具體的類型,也就是向類型參數(shù)傳值,格式為:
className variable<dataType1, dataType2> = new className<dataType1, dataType2>();
也可以省略等號右邊的數(shù)據(jù)類型,但是會產(chǎn)生警告,即:
className variable<dataType1, dataType2> = new className();
泛型的優(yōu)點(diǎn):使用泛型類時指明了數(shù)據(jù)類型,賦給其他類型的值會拋出異常,既不需要向下轉(zhuǎn)型,也沒有潛在的風(fēng)險。
除了定義泛型類,還可以定義泛型接口和泛型方法,使用泛型方法時不必指明參數(shù)類型,編譯器會根據(jù)傳遞的參數(shù)自動查找出具體的類型。
限制泛型的可用類型
通過 extends 關(guān)鍵字可以限制泛型的類型
public <T extends Number> T getMax(T array[]){
T max = null;
for(T element : array){
max = element.doubleValue() > max.doubleValue() ? element : max;
}
return max;
}
<T extends Number> 表示 T 只接受 Number 及其子類,傳入其他類型的數(shù)據(jù)會報錯。這里的限定使用關(guān)鍵字 extends,后面可以是類也可以是接口。但這里的 extends 已經(jīng)不是繼承的含義了,應(yīng)該理解為 T 是繼承自 Number 類的類型。