一、泛型
(官方定義):泛型的出現是JDK 1.5以後,它的本質是參數化類型的應用,可以用在類、接口和方法的創建中,分別稱爲泛型類、泛型接口和泛型方法。
我自己的理解是:泛型類似於方法中參數。只是泛型把數據的類型作爲參數傳遞,就是將當前我們需要操作的數據的類型指定爲參數,用到的時候,再具體指定他對應的類型。
在項目開發中我沒有嘗試過完全不使用泛型的情況,在我開始寫代碼的時候已經在使用泛型了。雖然沒有完全掌握泛型的原理,但已經在簡單的使用了。寫了個簡單的小例子感受了一下。(被舉了很多次的例子)
import java.util.ArrayList;
/**
* 不使用泛型的例子
*
*/
public class Generic {
public static void main(String[] args) {
// TODO Auto-generated method stub
ArrayList arrayList=new ArrayList();
arrayList.add("caka");
arrayList.add(100);
arrayList.add(2.3f);
for (int i = 0; i < arrayList.size(); i++) {
String temp = (String) arrayList.get(i);
System.out.println(temp);
}
}
}
運行這段代碼報java.lang.ClassCastException異常,強制類型轉換的時候出錯。這裏代碼的錯誤寫的很明顯,arrayList中默認存放的是Object類型的值,現在存放了三種類型int,float,string,是沒有任何問題的。但是在獲取arrayList中值的時候,我們無法確定取出的值是什麼類型,所以會在運行時出現ClassCastException的異常。
import java.util.ArrayList;
/**
* 使用泛型的例子
*
*/
public class Generic {
public static void main(String[] args) {
ArrayList <String> arrayList=new ArrayList <String>();
arrayList.add("caka");
arrayList.add("100");
// arrayList.add(2.3f);
for (int i = 0; i < arrayList.size(); i++) {
String temp = (String) arrayList.get(i);
System.out.println(temp);
}
}
}
上面第一個例子,可以理解成arrayList在將對象add之後,並不能記錄每個add後對象的本身類型,編譯的時候全部默認爲Object類型了,所以在運行的時候無法確定獲取到的下一個值是什麼類型。但在使用泛型的時候,會在arrayList申明時給定參數,arrayList.add(1); arrayList.add(2.3f);在編譯的時候就會報錯。
結合泛型定義,在上個例子中, ArrayList <String> arrayList=new ArrayList <String>()裏String相當於是類型實參,那應該有相應的類型形參。且get()方法的返回結果也直接是此形參類型對應的類型(即類型實參)
二、泛型的定義和使用
泛型可以用於類、接口和方法上(泛型類、泛型接口和泛型方法)
1.泛型類的定義
public class Generic {
public static void main(String[] args) {
Colleage<String> colleage=new Colleage<String>("undergraduate");
String studentName=colleage.getStudent();
System.out.println(studentName);
colleage.setStudent("postgraduate");
studentName=colleage.getStudent();
System.out.println(studentName);
}
}
//泛型類的定義
class Colleage<T>{
private T student;
public Colleage(T student){
this.student=student;
}
public T getStudent() {
return student;
}
public void setStudent(T student) {
this.student = student;
}
}
上面的泛型類中,T表示泛型形參,用於接收來自外部使用時候傳入的類型實參,上例中的類型實參就爲String類型。泛型的類型參數只能是類類型(包括自定義類),不能是簡單類型。
定義的泛型類不一定必須要傳入泛型實參,如果傳入實參,就會做類型限制。不傳入參數也是被允許的,在泛型類中使用泛型的方法可以是任意類型。比如:
Colleage colleage=new Colleage("undergraduate");
String studentName=colleage.getStudent();
System.out.println(studentName);
之前好奇泛型形參E接受不同傳入的泛型實參,生成的對象實例的類型是相同還是不同,測試了一下,發現是相同的。
public class Generic {
public static void main(String[] args) {
Colleage<String> colleage1=new Colleage<String>("undergraduate");
Colleage<Integer> colleage2=new Colleage<Integer>(985);
System.out.println(colleage1.getClass()==colleage2.getClass());
}
}
程序運行結果是true。可見雖然傳入了不同的類型實參,但並沒有真正意義上生成不同的類型。傳入不同泛型實參的泛型類在內存上只有一個,還是上例中的Colleage類型。(涉及類型擦除)
2.泛型接口的定義(簡單舉例)
public interface GenericInterface<T,U> {
void getGeneric(T t,U u);
}
實現泛型接口的類沒有傳入泛型實參的時候,與泛型類的定義相同,在聲明類的時候,需要將泛型的聲明也一起加到類中。
public class Generic <T,U> implements GenericInterface<T,U> {
void getGeneric(T t,U u){
}
}
泛型接口的實現類傳入了確定的泛型實參。相當於可以生產一個GenericInterface接口,傳入無數個實參,
public class Generic implements GenericInterface<String, Double> {
@Override
public void getGeneric(String s, Double d) {
System.out.println(s);
System.out.println(d);
}
public static void main(String[] args) {
Generic generic=new Generic();
generic.getGeneric("19960101", 11.11);
}
}
3.泛型方法
public static <T, U> T get(T t, U u) {
if (u != null)
return u;
else
return t;
}
泛型方法在聲明的時候要在方法返回類型之前聲明類型參數
那如果我們在調用泛型方法的時候,有時候需要限制類型參數的類型範圍,比如,比較數字大小的方法類型需要限定爲Number或者其子類的實例。即有界參數。
public static <T> T maximum(T x,T y,T z) {
T max=x;
if(y.compareTo(max)>0){//1
max=y;
}
if(z.compareTo(max)>0){//2
max=z;
}
return max;
}
上面的方法會在1和2處編譯錯誤。編譯之前,還在定義這個泛型方法的時候,泛型類型T的類型不能確定。所以,只能默認T爲原始類型Object。所以它只能調用來自於Object的那幾個方法,而不能調用compareTo方法。類型限定就很有必要了。由於compareTo方法的使用需要實現Comparable接口。所有該泛型方法需要做如下修改:
public static <T extends Comparable<T>> T maximum(T x,T y,T z) {
T max=x;
if(y.compareTo(max)>0){
max=y;
}
if(z.compareTo(max)>0){
max=z;
}
return max;
}
需要注意的是:
1、不管是限定類還是接口,統一都使用關鍵字 extends
2、有多個限定需要使用&符號給出多個限定。
public static <T extends Comparable&Serializable> T maximum(T x,T y,T z)
3.如果限定既有接口也有類,那麼類必須只有一個,並且放在首位置
public static <T extends Object&Comparable&Serializable> T maximum(T x,T y,T z)