造輪子的時候不敢用不會用泛型?那你看這篇就夠了!

閱讀本文解決什麼問題?

解決許多java開發 或者android開發 在平時寫一些基礎架構,或者是造一些輪子的時候不敢用泛型,用很差泛型的問題。 甚至有些人使用泛型的時候報錯都只會用idea提示的方法來修改代碼,殊不知這樣改的緣由,也不知道強轉泛型會有什麼惡果。java

泛型用來解決什麼問題

先定義一個模仿List 的泛型list。 咱們來看看這個乞丐版的list能幫咱們作什麼事android

public class CustomList<T> {
    Object[] array = new Object[0];

    public T get(int index) {
        return (T) array[index];
    }

    public void add(T instance) {
        array[array.length - 1] = instance;
    }
}
複製代碼

看看怎麼使用他bash

CustomList<String> customList = new CustomList<>();
        customList.add("hahahaha");
        String c = customList.get(0);
複製代碼

到這,咱們來看看 到底有啥好處。 首先看這個add方法,有了泛型之後,咱們就不須要擔憂類型轉換錯誤了。 由於咱們在定義的時候 指定了泛型的類型,因此若是咱們在調用add方法的時候傳了一個 非string類型的 那麼ide就會報錯了,即便你不用ide 用記事本寫,你編譯起來也會報錯的。 這就是靜態語言的好處了, 不少bug 在編譯的時候告訴你 不用像js 那麼蛋疼。markdown

而後再看看get 這個函數,想一下 若是沒有泛型的話, 咱們get出來的值 是必定要強轉成string才能賦值給c的, 可是如今有了泛型, 因此你能夠直接get出來,這個類型轉換的東西 早就幫你作好了。架構

總結一下泛型的好處:app

  1. 避免運行時出錯,編譯時就告訴你
  2. 方便你使用,省略強制類型轉換的代碼

泛型爲何不能夠是靜態的?

這邊能夠想一下,爲何泛型不能用靜態的去定義?你怎麼改都是沒法突破這個規則,是沒法編譯成功的。ide

前面的例子咱們能夠知道,泛型主要用來能夠初始化每一個實例的。 注意是每一個實例,他是動態肯定的,函數

取決於你當時使用的時候 傳的是什麼參數,好比List<Object> List<String> List<Teacher>ui

對於一個靜態變量來講 你若是用泛型 那就會亂套了。 例如咱們上面截圖的例子你用泛型會發生什麼?idea

static Object ins? static String ins? static Teacher ins? 你們都叫ins,那我怎麼知道 這個ins

到底應該是哪一個類型的? 靜態變量 全局惟一啊。 因此泛型是絕對不能用static來修飾的

這個地方必定要想明白了,想明白了,對你理解泛型是有好處的。

泛型的一種錯誤寫法

這種就是一種典型的錯誤寫法,明明接口中有泛型的,結果實體類中 把這個泛型給抹掉了。

雖然能夠編譯經過,可是這種寫法就毫無心義了。

這種纔是正確的寫法,和前面那種錯誤的寫法相比 咱們明顯能夠省略一次強制類型轉換。

你們能夠比對一下這2種寫法 和 文章開頭泛型的2個優勢。仔細體會一下。

如何正確extends泛型

泛型限制

interface IShop<T> {
    T buy(float price);
}


interface IPhoneShop2<T> extends IShop<T> {
    void repair(T phone);
}
複製代碼

前面咱們說道 ,泛型最大的好處就是方便使用,好比上面的代碼 咱們使用起來就很輕鬆如意,可是由於這樣的寫法 太隨意 因此要加一層限制。 上面的代碼中,咱們明明是一個手機商店,但實際使用的時候 卻能夠隨便傳, 傳String 傳Apple 傳啥都行。 這和設計者的本意是不一致的。

因此泛型還能夠加限制

interface Phone {

}

interface IPhoneShop2<T extends Phone> extends IShop<T> {
    void repair(T phone);
}

複製代碼

這樣一來就能夠限制咱們使用時的類型,限制他必定得是Phone的類型才行。 考慮到java 是支持多接口,可是不支持多繼承的,泛型的限制也遵循這個規定。

泛型限制在list中的迷惑性

來說講泛型中一個令不少人想不通的地方

定義一個水果 而後有蘋果和香蕉

interface TFruit {

}

class Apple2 implements TFruit {
}

class Banana2 implements TFruit {
}
複製代碼

而後咱們看看他們的使用

報紅的地方爲何報錯 是不少人想不明白的地方嗎,咱們的apple 命名是fruit的子類啊,爲啥報錯?

換個角度來思考一下這個問題:

因此對於 list 的 泛型來講, 他的類型 是動態肯定的, 是沒辦法在編譯期 肯定的, 因此你須要保證他 在= 兩邊 泛型都是絕對一致的 才能聲明成功,不然一定失敗

繼續看:

這個例子其實不難理解 爲何add 方法不能編譯經過。

看到這,我相信不少人 都想告辭了。。。這tmd 泛型限制真多,咋用?不用了,之後本身造輪子自動屏蔽泛型了。

不要緊 耐心一下,咱們再縷一遍。

// =左邊: 表明 我想要一個水果  =右邊 :我給你個蘋果  邏輯沒問題 編譯經過
        TFruit fruit = new Apple2();
        // =左邊: 表明 我想要一個水果的list 任意的水果 =右邊 :我給你個任意水果的list 邏輯沒問題 編譯經過
        List<TFruit> tf1 = new ArrayList<TFruit>();
        //既然是個水果的list 那我 add 蘋果香蕉 確定沒問題
        tf1.add(new Apple2());
        tf1.add(new Banana2());


        // =左邊: 表明 我想要一個水果的list 任意的水果  =右邊 :我給你一個蘋果的list
        //這樣編譯確定不經過,由於我想要的是水果的list 你卻給我一個蘋果的list 這樣你讓我就沒辦法玩了
        // 我想要水果 你只給我蘋果 那香蕉 葡萄 西瓜 我就沒辦法要了,因此你確定不行 編譯不過
        List<TFruit> tf2 = new ArrayList<Apple2>();



        //=左邊: 表明 我想要一個list,這個list 必須是一個水果的類型,且只能是一種水果的類型   =右邊 :我給你一個蘋果的list
        //符合要求 編譯經過
        List<? extends TFruit> tf3 = new ArrayList<Apple2>();
        //我這個tf3 要求的是必須是一種水果的類型,可是我並不知道是那種類型,多是水果 多是葡萄 多是香蕉
        // 因此你直接往我這塞一個肯定好的水果  我確定是不接受的,編譯確定失敗
        tf3.add(new Apple2());
        tf3.add(new Banana2());
複製代碼

?extends 好像有點蠢?

前面的文章看完,是否是以爲 這個?extends 有點蠢了,實際上 他在某種場景下 是 十分有用的(廢話 否則java爲啥要這麼設計)

仍是上面的水果,咱們增長一個方法 返回對應水果的價格

interface TFruit {
    int getPrice();
}

class Apple2 implements TFruit {
    @Override
    public int getPrice() {
        return 1;
    }
}

class Banana2 implements TFruit {
    @Override
    public int getPrice() {
        return 2;
    }
}
複製代碼

看看會有什麼問題

看這個函數的參數, 這個函數的參數 意思是 我想要一個list ,這個list裏面 能夠聽任何水果, 只要是水果就行,

可是在調用的時候 咱們給他的 倒是蘋果的list 和 香蕉的list ,這就不是他想要的了,我想要任意類型的水果 你卻給我 蘋果或者是香蕉的,你幫我指定了具體類型 那確定是不能夠的。

因此這個時候 ? extends 就出場了

改完之後 就直接編譯成功了:

回想一下上一小節的內容,這個? extends 不就是表明 想要任意一種水果嗎

你既然想要的是任意 一種水果,那我給你蘋果或者香蕉 確定是ok的。

大家使用的泛型埋坑了嗎?

並且是運行期間報錯了。後果比較嚴重,不易察覺。

一個香蕉固然不能轉成蘋果。

平時寫代碼的時候必定不要這麼寫。

?super 又是啥,怎麼用。

改爲

就能夠, 這裏怎麼理解?

加上? super就表明 等號右邊的東西 你只要能夠接受一個蘋果的list就能夠了。

相關文章
相關標籤/搜索