最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

Java中的紙老虎之泛型

 更新時間:2021年09月20日 10:44:55   作者:春風(fēng)~十一載  
泛型在java中有很重要的地位,在面向?qū)ο缶幊碳案鞣N設(shè)計模式中有非常廣泛的應(yīng)用。對java的泛型特性的了解僅限于表面的淺淺一層,直到在學(xué)習(xí)設(shè)計模式時發(fā)現(xiàn)有不了解的用法,才想起詳細的記錄一下。

泛型,其實算是Java當(dāng)中比較難的語法了,很多人一開始都對其一知半解,也很害怕閱讀帶泛型的源碼,雖然看起來語法很難,但當(dāng)你理解后會覺得很簡單,其實只是一個紙老虎罷了。下面,我將會用非常簡單易懂的方式帶你去理解它,相信你在認真看完后會有非常大的收獲,從此不會再畏懼它!

在這里插入圖片描述

一. 泛型的定義

這里大家可以不必去看網(wǎng)上的有些定義,因為相對于比較學(xué)術(shù)化,只需記住泛型可以在程序設(shè)計中指定某種類型,讓程序的設(shè)計更加規(guī)范化即可

二. 為什么要用到泛型

了解到了泛型是什么后,那我們來討論討論為什么要用泛型這個語法,這個語法到底是干什么的?別急,下面,我先給大家舉一個例子:

class Stack {
    public Object[] objects;
    public int top;

    public Stack() {
        this.objects =new Object[10];
    }

    public void push(Object obj) {
        objects[this.top++] = obj;
    }

    public Object get() {
        return objects[this.top-1];
    }
}

大家可以看看這是在干什么呢?這是我們自己寫了一個棧,然后將棧里的數(shù)組類型設(shè)置成Object類型,這樣的話這個棧里任意類型的數(shù)據(jù)都可以存放了(Object類是任何類的父類,不管插入什么類型的數(shù)據(jù),都可以發(fā)生向上轉(zhuǎn)型)

下面,我們來測試一下

public class Test {
    public static void main(String[] args) {
        Stack stack=new Stack();
        stack.push(1);
        stack.push(2);
        stack.push("123");
        String str=(String)stack.get();
    }
}

可以看到,我們可以向自己寫的棧里放入整形以及字符串等等任何類型的數(shù)據(jù),但注意一下取出數(shù)據(jù)的時候要進行強制類型轉(zhuǎn)換
以上這樣寫,可以向棧里存放任何類型的數(shù)據(jù),比較通用,其優(yōu)點也可以變成缺點,正因為太通用了,使代碼的規(guī)范性降低,看起來比較凌亂,這時候,我們可以考慮使用泛型,這樣可以在類中或者Java集合中存放特定的數(shù)據(jù)(使用Java集合時,一般都要用到泛型,而自定義的類型中可以使用泛型也可以不使用)

三. 泛型的寫法

以自定義的類型為例,寫法為在類名后面加上尖括號,里面寫上一個字母(注意,此處寫任何字母都可以,只起到一個標(biāo)記這個類為泛型類的作用)

class Stack<T>

而在new對象時,以棧里只能存放整形為例,前面的尖括號必須寫基本數(shù)據(jù)類型對應(yīng)的包裝類,而后面的尖括號可以不用寫,示例如下:

Stack<Integer> stack = new Stack<>();

補一下Java中的基本數(shù)據(jù)類型與對應(yīng)的包裝類:

在這里插入圖片描述

因此,我們前面寫的自定義的??梢詫懗梢韵滦问剑ㄒ源娣耪螢槔?/p>

class Stack<T> {
    public T[] objects;
    public int top;

    public Stack() {
        this.objects = (T[])new Object[10];
    }

    public void push(T obj) {
        objects[this.top++] = obj;
    }

    public T get() {
        return objects[this.top-1];
    }
}
 Stack<Integer> stack = new Stack<>();
        stack.push(1);
        stack.push(2);
        int ret = stack.get();
        System.out.println(ret);

特別注意此處:public Stack() { this.objects = (T[])new Object[10]; }
這里不能寫成this.objects=new T[10];
原因:
1. 不能new泛型類型的數(shù)組
2. 也可理解為泛型是先檢查后編譯的,如果new泛型類型的數(shù)組的話,編譯器檢查時并不知道T是什么類型的,因此會報錯。而編譯的時候才會進行擦除機制,都會將其轉(zhuǎn)換為Object類型
3. 正因為有這個擦除機制,這里才能進行數(shù)組整體強制類型轉(zhuǎn)換(一般數(shù)組不能整體進行強制類型轉(zhuǎn)換),因為泛型只是在編譯的時候起作用,而實際運行時都會被擦除成Object類型,即實際運行時是沒有泛型這個概念的,也即實際運行時類型都是一樣的,所以T本質(zhì)上是object類型的,所以此代碼等價于不進行強制類型轉(zhuǎn)換?。?!
4.而直接指定泛型的代碼(不是T) 比如:Stack<Integer>和Stack<Character>都是在運行時直接把尖括號里的類型擦掉了,可以看到直接打印的結(jié)果(并沒有打印出類型):

在這里插入圖片描述

在這里插入圖片描述

此處注意多理解理解

在這里插入圖片描述

四. 泛型的使用實例

1. 求最大值

以上就是泛型的一個重要知識點了,但光看是不夠的,還是得通過例子讓大家有一個更為深入的理解,比如,如何寫一個泛型類來求數(shù)組的最大值呢?
基本的框架大概是這樣的:(沒看懂的小可愛好好看看上面講的內(nèi)容哦)

class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max < array[i]) {
                max = array[i];
            }
        }
        return max;
    }
}

但是此代碼if(max < array[i])會報錯,為什么呢?因為將來給T傳的值一定是一個引用類型,引用類型不能直接比較大于或者小于的,是要用Comparable或Comparator接口里的方法比較的,因為泛型在編譯的時候會被擦除成Object類型,但Object類本身并沒有實現(xiàn)ComparableComparator接口,所以我們要控制其不要擦除到Object類,所以要給泛型指定一個邊界

具體寫法如下:

class Algorithm<T extends Comparable<T>> {
    public T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            //max < array[i]
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}

class Algorithm<T extends Comparable<T>>

注意,extends叫做上界,此代碼代表的意思為T這個泛型類會擦除到實現(xiàn)了Comparable接口的地方,換句話說,這個T類型一定是實現(xiàn)了Comparable接口的
同理:這個代碼public class MyArrayList<E extends Number> { ... }代表E為Number的子類或Number本身
下面讓我們來用一下:

 Algorithm<Integer> algorithm1 = new Algorithm<>();
        Integer[] integers = {1,2,13,4,5};
        Integer ret = algorithm1.findMax(integers);
        System.out.println(ret);

運行結(jié)果如下:

在這里插入圖片描述

成功了!

2. 優(yōu)化

經(jīng)過上面的努力,我們已經(jīng)寫出了一個泛型類來求一個數(shù)組的最大值了,但是,上面的例子是一個整形數(shù)組,那么我們能不能在數(shù)組里存放別的類型去比較呢?答案是可以的,但是我們還得去new一個對象,例如:Algorithm<String> algorithm2 = new Algorithm<>();這樣很麻煩。但是我們可以將求最大值的方法設(shè)置成靜態(tài)的class Algorithm2 <T>,因為是靜態(tài)的方法,不需要new對象,所以就沒有在new對象時指定泛型的過程了,所以沒必要給方法后加尖括號,但是去掉之后,代碼又會被錯:

在這里插入圖片描述

我們可以這樣修改:

class Algorithm2 {
    public static<T extends Comparable<T>> T findMax(T[] array) {
        T max = array[0];
        for (int i = 1; i < array.length; i++) {
            if(max.compareTo(array[i]) < 0) {
                max = array[i];
            }
        }
        return max;
    }
}

此方法public static<T extends Comparable<T>> T findMax(T[] array){}叫做泛型方法

下面繼續(xù)帶大家來用一下:

public static void main(String[] args) {
        Integer[] integers = {1,2,13,4,5};
        //會根據(jù)形參的類型推導(dǎo)出整個泛型的類型參數(shù)
        Integer ret = Algorithm2.findMax(integers);
        System.out.println(ret);
        Integer ret2 = Algorithm2.<Integer>findMax(integers);
        System.out.println(ret2);
    }

注意,ret1寫法和ret2寫法是一樣的,都可以
打印結(jié)果如下:

在這里插入圖片描述

五. 通配符

1. 基本寫法

通配符也是泛型的一種,下面我們來寫一個泛型方法來打印集合中的元素

class Test {

    public static<T> void print(ArrayList<T> list) {

        for (T t : list) {
            System.out.println(t);
        }
    }

這個寫法很簡單,上文都講過了,那么讓我們來試著用一下吧:

public static void main(String[] args) {
        ArrayList<Integer> list = new ArrayList<>();
        list.add(1);
        list.add(2);
        list.add(3);
        Test.print(list);
    }

打印的結(jié)果如下:

在這里插入圖片描述

除了以上這種寫法,我們還可以將其改成通配符的寫法,先給大家上代碼:

//?代表通配符  擦除機制  Object
    public static void print2(ArrayList<?> list) {
        for (Object t : list) {
            System.out.println(t);
        }
    }
}

此處for (Object t : list)必須這樣寫,因為通配符也是有擦除機制的,會在編譯器編程Object類型。

2. 上界

語法:<? extends 上界>

示例:

public static void printAll(MyArrayList<? extends Number> list) {
...
    } 

代表可以傳入類型實參是 Number 子類的任意類型的 MyArrayList
所以以下調(diào)用都是正確的:

printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Double>());
printAll(new MyArrayList<Number>());

以下調(diào)用都是錯誤的:

printAll(new MyArrayList<String>());
printAll(new MyArrayList<Object>());

3. 下界

下界和上界的用法很類似

語法:<? super 下界>

示例:

public static void printAll(MyArrayList<? super Integer> list) {
...
}

代表可以傳入類型實參是 Integer 父類的任意類型的 MyArrayList
所以以下調(diào)用是正確的:

printAll(new MyArrayList<Integer>());
printAll(new MyArrayList<Number>());
printAll(new MyArrayList<Object>());

以下調(diào)用是錯誤的:

printAll(new MyArrayList<String>());
printAll(new MyArrayList<Double>());

六. 泛型的限制

學(xué)習(xí)完后,我們應(yīng)該注意泛型使用過程中以下一些限制:

泛型類型參數(shù)不支持基本數(shù)據(jù)類型

無法實例化泛型類型的對象

無法使用泛型類型聲明靜態(tài)的屬性

無法使用 instanceof 判斷帶類型參數(shù)的泛型類型(因為被擦除機制擦除了)

無法創(chuàng)建泛型類數(shù)組

無法 create、catch、throw 一個泛型類異常(異常不支持泛型)

泛型類型不是形參一部分,無法重載

在這里插入圖片描述

好啦,本次泛型知識點的分享就先告一段落了,整理不易,但如果能幫到大家很開心了。也希望大家多理解理解,不論是剛開始學(xué)習(xí)還是復(fù)習(xí),都值得仔細揣摩哦!一起加油吧!

到此這篇關(guān)于Java中的紙老虎之泛型的文章就介紹到這了,更多相關(guān)Java 泛型內(nèi)容請搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • Mybatis的parameterType造成線程阻塞問題分析

    Mybatis的parameterType造成線程阻塞問題分析

    這篇文章主要詳細分析了Mybatis的parameterType造成線程阻塞問題,文中有詳細的解決方法,及相關(guān)的代碼示例,具有一定的參考價值,感興趣的朋友可以借鑒閱讀
    2023-06-06
  • Mybatis-Plus同時使用邏輯刪除和唯一索引的問題及解決辦法(報數(shù)據(jù)重復(fù)Duplicate entry的問題)

    Mybatis-Plus同時使用邏輯刪除和唯一索引的問題及解決辦法(報數(shù)據(jù)重復(fù)Duplicate entry的

    在開發(fā)中,我們經(jīng)常會有邏輯刪除和唯一索引同時使用的情況,但當(dāng)使用mybatis plus時,如果同時使用邏輯刪除和唯一索引,會報數(shù)據(jù)重復(fù)Duplicate entry的問題,如何解決這個問題呢,小編給大家分享Mybatis-Plus同時使用邏輯刪除和唯一索引的問題及解決辦法,一起看看吧
    2023-11-11
  • java后端返回數(shù)據(jù)給前端時去除值為空或NULL的屬性、忽略某些屬性代碼示例

    java后端返回數(shù)據(jù)給前端時去除值為空或NULL的屬性、忽略某些屬性代碼示例

    在Java開發(fā)中我們處理JSON數(shù)據(jù)時經(jīng)常會遇到空值(null)的情況,這篇文章主要給大家介紹了關(guān)于java后端返回數(shù)據(jù)給前端時去除值為空或NULL的屬性、忽略某些屬性的相關(guān)資料,文中通過代碼介紹的非常詳細,需要的朋友可以參考下
    2024-07-07
  • Spring循環(huán)依賴的處理方法

    Spring循環(huán)依賴的處理方法

    循環(huán)依賴是指兩個或多個組件之間相互依賴,形成一個閉環(huán),從而導(dǎo)致這些組件無法正確地被初始化或加載,這篇文章主要介紹了Spring循環(huán)依賴的處理,需要的朋友可以參考下
    2023-08-08
  • JAVA導(dǎo)出EXCEL表格的實例教學(xué)

    JAVA導(dǎo)出EXCEL表格的實例教學(xué)

    在本文中我們給大家整理了關(guān)于JAVA導(dǎo)出EXCEL表格的實例教學(xué)以及相關(guān)知識點,需要的朋友們學(xué)習(xí)下。
    2019-02-02
  • Java中的TreeSet源碼解讀

    Java中的TreeSet源碼解讀

    這篇文章主要介紹了Java中的TreeSet源碼解讀,TreeSet 是一個 有序集合,它擴展了 AbstractSet 類并實現(xiàn)了 NavigableSet 接口,對象根據(jù)其自然順序以升序排序和存儲,該 TreeSet 中使用 平衡樹,更具體的一個 紅黑樹,需要的朋友可以參考下
    2023-09-09
  • 淺談Java中的LinkedHashSet哈希鏈表

    淺談Java中的LinkedHashSet哈希鏈表

    這篇文章主要介紹了淺談Java中的LinkedHashSet哈希鏈表,LinkedHashSet 是 Java 中的一個集合類,它是 HashSet 的子類,并實現(xiàn)了 Set 接口,與 HashSet 不同的是,LinkedHashSet 保留了元素插入的順序,并且具有 HashSet 的快速查找特性,需要的朋友可以參考下
    2023-09-09
  • java中的hashCode方法小例子

    java中的hashCode方法小例子

    這篇文章主要介紹了java中的hashCode方法小例子,有需要的朋友可以參考一下
    2013-12-12
  • 解讀@SelectProvider的使用方法

    解讀@SelectProvider的使用方法

    這篇文章主要介紹了@SelectProvider的使用方法,具有很好的參考價值,希望對大家有所幫助,如有錯誤或未考慮完全的地方,望不吝賜教
    2024-08-08
  • 從Mybatis-Plus開始認識SerializedLambda的詳細過程

    從Mybatis-Plus開始認識SerializedLambda的詳細過程

    這篇文章主要介紹了從Mybatis-Plus開始認識SerializedLambda,本文通過實例代碼給大家介紹的非常詳細,需要的朋友可以參考下
    2024-07-07

最新評論

沧州市| 瑞金市| 乐清市| 团风县| 柳林县| 波密县| 茌平县| 绿春县| 柏乡县| 苍南县| 永兴县| 大埔县| 宣汉县| 青海省| 凌源市| 潜山县| 兴国县| 通榆县| 巨鹿县| 九龙城区| 宁德市| 娄底市| 松阳县| 龙山县| 东至县| 沙湾县| 普兰县| 德令哈市| 元阳县| 兴国县| 巴中市| 林西县| 明溪县| 筠连县| 巴林左旗| 株洲市| 北碚区| 阿巴嘎旗| 凭祥市| 临潭县| 苏州市|