一起來理解Java中的泛型

2022-05-18 19:01:09
本篇文章給大家帶來了關於的相關知識,其中主要介紹了關於泛型的相關問題,包括了自定義泛型類、自定義泛型方法、自定義泛型介面等等內容,下面一起來看一下,希望對大家有幫助。

推薦學習:《》

  • 泛型:是JDK5中引入的特性,可以在編譯階段約束操作的資料型別,並進行檢查。
  • 泛型的格式:<資料型別>,注意:泛型只能支援參照資料型別
  • 集合體系的全部介面和實現類都是支援泛型的使用的。

優點:

  • 統一資料型別。
  • 把執行的問題提前到編譯期間,避免了強制型別轉換可能出現的問題,因為編譯階段型別便可以確定下來。
public static void main(String[] args) {
        List<String> list = new ArrayList<>();
        list.add("石原里美");
        list.add("工藤靜香");
        list.add("朱茵");
        for (String s : list) {
            System.out.println(s);
        }
    }
輸出結果:
石原里美
工藤靜香
朱茵

並且泛型還可以在很多地方進行定義,比如在類後面就是泛型類、方法宣告上就是泛型方法、介面後面就是泛型介面。接下來我們共同來學習一下這些泛型是如何使用的:

自定義泛型類

概念

  • 定義類的同時定義了泛型的類就是泛型類。
  • 泛型類的格式:修飾符 class 類名<泛型變數> { }
public class MyArrayList<E>{    }
  • 作用:編譯階段可以指定資料型別,類似於集合的作用

實戰教學

現建立一個泛型類,實現基本的增加、刪除操作,以此來具體瞭解其用法:

//泛型類MyArrayLIst
public class MyArrayLIst<E> {
    public void add(E e){

    }
    public void remove(E e){

    }
}
//main
public static void main(String[] args) {
        MyArrayLIst<String> list = new MyArrayLIst<>();
        //通過對泛型的設定,實現對資料專一處理
        list.add("石原里美");
        list.add("工藤靜香");
        list.remove("工藤靜香");
    }

泛型類的原理:

把出現泛型變數的地方全部替換成傳輸的真實的資料型別。

通過認真觀察,其實不難去發現,泛型類與普通類的最大區別在於在呼叫方法的時候可以統一的對同一種資料進行處理,不會涉及到其他的資料型別,從一定程度上避免了強制型別轉化時可能會出現的問題。

自定義泛型方法

概念

  • 定義方法的同時定義了泛型的方法就是泛型方法。
  • 泛型方法的格式:修飾符<泛型變數> 返回值型別 方法名(形參列表){ }
public <E> void view(E e){    }
  • 作用:方法中可以使用泛型接收一切實際型別的引數,方法更具備通用性。
  • 注意:泛型方法需要區別於泛型類中所定義的方法,雖然它們也在使用泛型,但是該泛型不是其定義的,而是泛型類定義的。

實戰教學

無論傳入何種型別的陣列,都可以返回它的內容,即實現Arrays.toString()的作用

public static void main(String[] args) {
        String [] name = {"石原里美","工藤靜香","朱茵"};
        view(name);
        Integer [] age = {18,19,20};
        view(age);
    }
    public static  <T> void view(T[] arr){
        StringBuilder list = new StringBuilder();
        for (int i = 0; i < arr.length; i++) {
            list.append(arr[i]).append("\t");
        }
        System.out.println(list);
    }

通過實現對泛型方法的定義,可以實現多種資料型別的接收,應用範圍更加廣泛。

自定義泛型介面

概念

  • 使用泛型定義的介面就是泛型介面。
  • 泛型介面的格式:public interface People<E>{ }
public interface People <E>{    }
  • 作用:泛型介面可以讓實現類選擇當前功能需要操作的資料型別

實戰教學

定義一個People介面,實現對老師Teacher類、學生Student等類的操作

//People介面
public interface People <E>{
    void run(E e);
    void height(E e);
}
//Student類
public class Teacher {

}
//實現類Fantype
public class Fantype implements People<Teacher> {

    @Override
    public void run(Teacher teacher) {

    }

    @Override
    public void height(Teacher teacher) {

    }
}

通過對上述程式碼的觀察,可以發現,People後定義的是什麼型別,那麼該實現類只能對該種資料型別進行操作,其他型別不可以進行此操作。

萬用字元和上下限

萬用字元

  • ?可以在「使用泛型」的時候代表一切型別
  • E T K V是在定義泛型的時候用的

假設現在有一場為學生和老師而舉辦的比賽,需要比較速度究竟誰更快,分別建立一定數量的物件並將其傳入集合之中。然而當我們將這兩個集合分別傳入方法中的時候,會發現,學生物件集合list2出現報錯,為什麼呢?原因是因為資料型別不同,那麼該如何使得兩種型別都可以傳入呢?或許這個時候就會有人說了:「既然兩個類都是People的子類,那麼為什麼不定義它的泛型是People呢?」這個想法很好,但是我們需要明確一點的是子類與父類別雖然是有關係的,但是定義之後的集合是沒有關係的,所以這裡是行不通的。

//main
//老師物件集合
ArrayList<Teacher> list1 = new ArrayList<>();
list1.add(new Teacher());
list1.add(new Teacher());
pk(list1);
//學生物件集合
ArrayList<Student> list2 = new ArrayList<>();
list2.add(new student());
list2.add(new student());
pk(list2);//由於pk方法的形參是泛型為Teacher的集合,所以會報錯
//父類別
class People{

    }
//子類
class Teacher extends People{

    }
class student extends People{

    }
//pk方法:
public static void pk(ArrayList<Teacher> people){
}

應對這個問題,我們可以便可以將本篇文章引入的知識「萬用字元」放在實際應用中解決問題了,通過其簡短的概念「?可以在‘使用泛型’的時候代表一切型別」就可以理解其作用了,這裡我們可以使用「?」共同代表兩種型別。

public static void pk(ArrayList<?> people){
//通過萬用字元?便可以將這個問題解決掉
    }

上下限

然而此時又出現一個問題,定義了一個dog類,試圖建立一些物件並傳入集合中混入比賽,這種當然情況當然是不允許發生的,然而?是可以表示任意型別的,並不能對其進行限制。因此上下限的作用就體現出來了:

  • 上限:<? extends 父類別>,傳入型別必須是該父類別或者是父類別的子類
  • 下限:<? super 子類>,傳入型別必須是該子類或者是子類的父類別
public static void pk(ArrayList<? extends People> people){
//通過上下限便可以將這個問題解決掉
//要求傳入的型別必須是People的子類才可以
    }

推薦學習:《》

以上就是一起來理解Java中的泛型的詳細內容,更多請關注TW511.COM其它相關文章!