(一)泛型學習筆記——基礎知識

一、泛型

(官方定義)泛型的出現是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)




發佈了33 篇原創文章 · 獲贊 51 · 訪問量 9萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章