泛型 -- 基本原理推導(不用再死記硬背)

泛型是什麼?

泛型是什麼呢?從字面意思來理解就是廣泛的類型(個人理解)。泛型是 jdk1.5 的產物,被業界大佬稱之爲 jdk 的里程碑事件。到底是什麼原因使得這樣的產物讓廣大 Java 程序員讚不絕口。聽我細細侃來。

引出泛型:

每件事物的產生必然有一定的道理,泛型亦是如此。
我們來看一下下面這個集合:

public class Ttest01 {

    public static void main(String[] args) {

        MySet set = new MySet();

		// 向集合中添加一個字符串
        set.add("abc");

        String info = (String) set.get(0);
        System.out.println(info);
	
		// 向集合中添加一個整數
        set.add(2);
		// 插入一個整數,取的時候除了我們自己沒有人知道插入的類型是什麼
		// 究竟強轉成什麼,不同的用戶有不同的選擇
        String info1 = (String) set.get(1);
        System.out.println(info1);
    }
}

// 集合類
class MySet{

    Object[] mySet = new Object[10];
    int idx = 0;
    // 向集合中插入一個元素
    public void add(Object value) {
        mySet[idx ++] = value;
    }

	// 獲取元素的值
    public Object get(int idx) {
        return mySet[idx];
    }
}

通過上面的樣例,代碼在編寫的過程中是不會報錯的,但是在實際運行過程中呢?
在這裏插入圖片描述
顯然代碼報錯了。
先不說代碼有錯的問題,假設給你一個這樣的集合,咱不知道集合中每個元素的數據類型,咱是不是要一個一個進行強制轉換呢?而且我們也不知道究竟應該轉成哪種類型纔不會報錯。(我要是項目經理,估計就被氣死了)

泛型應運而生:

既然一個集合中有String類型,有 Integer 類型,那麼我們能不能一個集合中只存儲 String ,一個集合只存 Integer 類型呢?顯然是可以的。
看代碼:

public class Ttest01 {

    public static void main(String[] args) {

        MySet1 set = new MySet1();

        set.add("abc");

        String info = (String) set.get(0);

        System.out.println(info);
    }
}


class MySet1{
    String[] mySet = new String[10];
    int idx = 0;
    public void add(String value) {
        mySet[idx ++] = value;
    }

    public String get(int idx) {
        return mySet[idx];
    }
}

當我們規定這個集合中只能存 String 類型時,那麼我們想插入一個 Integer 類型的數據時會出現什麼情況呢?
在這裏插入圖片描述
紅線警告了,說明我們只能向集合中插入 String 類型。

當指定集合中的具體類型有什麼好處呢?
1、給予每個使用該集合的用戶 明確的信息。
2、如果插入不同的數據類型會進行錯誤提示。
3、不再需要進行不確定的強制類型轉換

可能有的小夥伴會想,我們原來的集合既可以存儲String類型的,又可以存儲 Integer 類型的,這樣不好嗎?
別慌,相信現在你已經明白一點,原來的方式取出時是不方便的,並且對於一個不知道你的集合中各個元素的數據類型的用戶來說,使用起來是及其不方便的
還有一點,在後面會提到。

泛型推導:

說了這麼多廢話,終於到Boss出場了。
當我們想讓一個集合中都是 Integer 類型會怎麼做呢?

class MySet2{
    Integer[] mySet = new Integer[10];
    int idx = 0;
    public void add(Integer value) {
        mySet[idx ++] = value;
    }

    public Integer get(int idx) {
        return mySet[idx];
    }
}

我們上面的 String 類型是什麼樣的呢?

class MySet1{
    String[] mySet = new String[10];
    int idx = 0;
    public void add(String value) {
        mySet[idx ++] = value;
    }

    public Object get(int idx) {
        return mySet[idx];
    }
}

仔細觀察一下就會發現,這兩個類型裏面有很多重複的代碼,如果說 之後還會有 Double,Person、Dog 類型的,我們是不是要寫更多的代碼呢?瞭解 Java 的都
多少知道一點,就是代碼的複用

class MySet1{
    X[] mySet = new X[10];
    int idx = 0;
    public void add(X value) {
        mySet[idx ++] = value;
    }

    public X get(int idx) {
        return mySet[idx];
    }
}

看這個代碼,我們將兩份代碼中不同的部分用 X 替換掉,每次只調用這個是不是就 OK 了。

那麼如何傳遞這個 X 呢?

class MySet1<X>{
    X[] mySet = new X[10];
    int idx = 0;
    public void add(X value) {
        mySet[idx ++] = value;
    }

    public X get(int idx) {
        return mySet[idx];
    }
}

上面的方式是不健全的,說白了就是有問題的,在泛型類中是不可以直接 new X[10] 的,具體就不再詳細說了(原諒博主的尷尬,下面的例子效果是一樣的,具體看下面的例子吧)。
所以不得不通過另一個例子來說明問題了,實際上只要知道 X 是怎麼推出來的就行了

通過下面的例子我們看一下如何調用:

import org.omg.CORBA.Object;

import java.util.Arrays;

public class Ttest01 {

    public static void main(String[] args) {

        MySet1<String> set = new MySet1<String>();

        set.add("a");

        System.out.println(set.get());


    }
}

// 給予類一個放參數的位置
class MySet1<E>{
    private E value;
    public void add(E value) {
        this.value = value;
    }
    public E get() {
        return value;
    }
}

像方法一樣 加個參數就可以啦。

想讓集合中都是 Integer 類型怎麼辦呢?

      MySet1<Integer> set = new MySet1<Integer>();

所以根據需要修改不同的參數即可。

如果想集合中既有String又有Interger 呢?

	MySet1 set = new MySet1();

看下完整代碼:

import org.omg.CORBA.Object;

import java.util.Arrays;

public class Ttest01 {

    public static void main(String[] args) {

        MySet1 set = new MySet1();

        set.add("a");
        set.add("123");

        System.out.println(set.get());


    }
}


class MySet1<E>{
    private E value;
    public void add(E value) {
        this.value = value;
    }
    public E get() {
        return value;
    }
}

是沒問題的,運行結果也是沒問題的,可以自己嘗試一下。
所以說,泛型是原先集合的加強,在原來的基礎上進去強化。

類是對象的模板,泛型是類的模板

這句話通過上面的例子可以好好琢磨一下,根據泛型我們可以創建的不同的類,
MySet1< Integer >
MySet1< String >
仔細看看確實蠻有道理的,嘻嘻。

泛型好在哪裏?

下面是我從某個地方的論壇上看到的,感謝大佬,引用一下:

Java語言引入泛型的好處是安全簡單。泛型的好處是在編譯的時候檢查類型安全,並且所有的強制轉換都是自動和隱式的,提高代碼的重用率。

1,類型安全。 泛型的主要目標是提高 Java
程序的類型安全。通過知道使用泛型定義的變量的類型限制,編譯器可以在一個高得多的程度上驗證類型假設。沒有泛型,這些假設就只存在於程序員的頭腦中(或者如果幸運的話,還存在於代碼註釋中)。

2,消除強制類型轉換。 泛型的一個附帶好處是,消除源代碼中的許多強制類型轉換。這使得代碼更加可讀,並且減少了出錯機會。

3,潛在的性能收益。
泛型爲較大的優化帶來可能。在泛型的初始實現中,編譯器將強制類型轉換(沒有泛型的話,程序員會指定這些強制類型轉換)插入生成的字節碼中。但是更多類型信息可用於編譯器這一事實,爲未來版本的
JVM 的優化帶來可能。由於泛型的實現方式,支持泛型(幾乎)不需要 JVM
或類文件更改。所有工作都在編譯器中完成,編譯器生成類似於沒有泛型(和強制類型轉換)時所寫的代碼,只是更能確保類型安全而已。

後記:

基本就介紹完了,中間有點小尷尬,不過相信正在看的你一定可以理解的,如果有疑問的可以隨時問我,相互學習,共同進步。
如果感覺對您有幫助,點個贊,點個關注哦,感謝感謝。
加油!少年!

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章