成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

泛型就這么簡單

novo / 2985人閱讀

摘要:前言從今天開始進(jìn)入基礎(chǔ)的復(fù)習(xí),可能一個星期會有一篇的十道簡單算法,我寫博文的未必都是正確的如果有寫錯的地方請大家多多包涵并指正今天要復(fù)習(xí)的是泛型,泛型在中也是個很重要的知識點(diǎn),本文主要講解基礎(chǔ)的概念,并不是高深的知識,如果基礎(chǔ)好的同學(xué)可以當(dāng)

前言

從今天開始進(jìn)入Java基礎(chǔ)的復(fù)習(xí),可能一個星期會有一篇的<十道簡單算法>,我寫博文的未必都是正確的~如果有寫錯的地方請大家多多包涵并指正~

今天要復(fù)習(xí)的是泛型,泛型在Java中也是個很重要的知識點(diǎn),本文主要講解基礎(chǔ)的概念,并不是高深的知識,如果基礎(chǔ)好的同學(xué)可以當(dāng)復(fù)習(xí)看看~

一、什么是泛型?

Java泛型設(shè)計(jì)原則:只要在編譯時期沒有出現(xiàn)警告,那么運(yùn)行時期就不會出現(xiàn)ClassCastException異常.

泛型:把類型明確的工作推遲到創(chuàng)建對象或調(diào)用方法的時候才去明確的特殊的類型

參數(shù)化類型:

把類型當(dāng)作是參數(shù)一樣傳遞

<數(shù)據(jù)類型> 只能是引用類型

相關(guān)術(shù)語:

ArrayList中的E稱為類型參數(shù)變量

ArrayList中的Integer稱為實(shí)際類型參數(shù)

整個稱為ArrayList泛型類型

整個ArrayList稱為參數(shù)化的類型ParameterizedType

二、為什么需要泛型

早期Java是使用Object來代表任意類型的,但是向下轉(zhuǎn)型有強(qiáng)轉(zhuǎn)的問題,這樣程序就不太安全

首先,我們來試想一下:沒有泛型,集合會怎么樣

Collection、Map集合對元素的類型是沒有任何限制的。本來我的Collection集合裝載的是全部的Dog對象,但是外邊把Cat對象存儲到集合中,是沒有任何語法錯誤的。

把對象扔進(jìn)集合中,集合是不知道元素的類型是什么的,僅僅知道是Object。因此在get()的時候,返回的是Object。外邊獲取該對象,還需要強(qiáng)制轉(zhuǎn)換

有了泛型以后:

代碼更加簡潔【不用強(qiáng)制轉(zhuǎn)換】

程序更加健壯【只要編譯時期沒有警告,那么運(yùn)行時期就不會出現(xiàn)ClassCastException異常】

可讀性和穩(wěn)定性【在編寫集合的時候,就限定了類型】

2.1有了泛型后使用增強(qiáng)for遍歷集合

在創(chuàng)建集合的時候,我們明確了集合的類型了,所以我們可以使用增強(qiáng)for來遍歷集合!

        //創(chuàng)建集合對象
        ArrayList list = new ArrayList<>();

        list.add("hello");
        list.add("world");
        list.add("java");

        //遍歷,由于明確了類型.我們可以增強(qiáng)for
        for (String s : list) {
            System.out.println(s);
        }
三、泛型基礎(chǔ) 3.1泛型類

泛型類就是把泛型定義在類上,用戶使用該類的時候,才把類型明確下來....這樣的話,用戶明確了什么類型,該類就代表著什么類型...用戶在使用的時候就不用擔(dān)心強(qiáng)轉(zhuǎn)的問題,運(yùn)行時轉(zhuǎn)換異常的問題了。

在類上定義的泛型,在類的方法中也可以使用!

/*
    1:把泛型定義在類上
    2:類型變量定義在類上,方法中也可以使用
 */
public class ObjectTool {
    private T obj;

    public T getObj() {
        return obj;
    }

    public void setObj(T obj) {
        this.obj = obj;
    }
}

測試代碼:

用戶想要使用哪種類型,就在創(chuàng)建的時候指定類型。使用的時候,該類就會自動轉(zhuǎn)換成用戶想要使用的類型了。

    public static void main(String[] args) {
        //創(chuàng)建對象并指定元素類型
        ObjectTool tool = new ObjectTool<>();

        tool.setObj(new String("鐘福成"));
        String s = tool.getObj();
        System.out.println(s);


        //創(chuàng)建對象并指定元素類型
        ObjectTool objectTool = new ObjectTool<>();
        /**
         * 如果我在這個對象里傳入的是String類型的,它在編譯時期就通過不了了.
         */
        objectTool.setObj(10);
        int i = objectTool.getObj();
        System.out.println(i);
    }
3.2泛型方法

前面已經(jīng)介紹了泛型類了,在類上定義的泛型,在方法中也可以使用.....

現(xiàn)在呢,我們可能就僅僅在某一個方法上需要使用泛型....外界僅僅是關(guān)心該方法,不關(guān)心類其他的屬性...這樣的話,我們在整個類上定義泛型,未免就有些大題小作了。

定義泛型方法....泛型是先定義后使用的

    //定義泛型方法..
    public  void show(T t) {
        System.out.println(t);

    }

測試代碼:

用戶傳遞進(jìn)來的是什么類型,返回值就是什么類型了

    public static void main(String[] args) {
        //創(chuàng)建對象
        ObjectTool tool = new ObjectTool();

        //調(diào)用方法,傳入的參數(shù)是什么類型,返回值就是什么類型
        tool.show("hello");
        tool.show(12);
        tool.show(12.5);

    }
3.3泛型類派生出的子類

前面我們已經(jīng)定義了泛型類,泛型類是擁有泛型這個特性的類,它本質(zhì)上還是一個Java類,那么它就可以被繼承

那它是怎么被繼承的呢??這里分兩種情況

子類明確泛型類的類型參數(shù)變量

子類不明確泛型類的類型參數(shù)變量

3.3.1子類明確泛型類的類型參數(shù)變量

泛型接口

/*
    把泛型定義在接口上
 */
public interface Inter {
    public abstract void show(T t);

}

實(shí)現(xiàn)泛型接口的類.....

/**
 * 子類明確泛型類的類型參數(shù)變量:
 */

public class InterImpl implements Inter {
    @Override
    public void show(String s) {
        System.out.println(s);

    }
}
3.3.2子類不明確泛型類的類型參數(shù)變量

當(dāng)子類不明確泛型類的類型參數(shù)變量時,外界使用子類的時候,也需要傳遞類型參數(shù)變量進(jìn)來,在實(shí)現(xiàn)類上需要定義出類型參數(shù)變量

/**
 * 子類不明確泛型類的類型參數(shù)變量:
 *      實(shí)現(xiàn)類也要定義出類型的
 *
 */
public class InterImpl implements Inter {

    @Override
    public void show(T t) {
        System.out.println(t);

    }
}

測試代碼:

    public static void main(String[] args) {
        //測試第一種情況
        //Inter i = new InterImpl();
        //i.show("hello");

        //第二種情況測試
        Inter ii = new InterImpl<>();
        ii.show("100");

    }

值得注意的是:

實(shí)現(xiàn)類的要是重寫父類的方法,返回值的類型是要和父類一樣的!

類上聲明的泛形只對非靜態(tài)成員有效

3.4類型通配符

為什么需要類型通配符????我們來看一個需求.......

現(xiàn)在有個需求:方法接收一個集合參數(shù),遍歷集合并把集合元素打印出來,怎么辦?

按照我們沒有學(xué)習(xí)泛型之前,我們可能會這樣做:

public void test(List list){


    for(int i=0;i

上面的代碼是正確的,只不過在編譯的時候會出現(xiàn)警告,說沒有確定集合元素的類型....這樣是不優(yōu)雅的...

那我們學(xué)習(xí)了泛型了,現(xiàn)在要怎么做呢??有的人可能會這樣做:

public void test(List list){


    for(int i=0;i

這樣做語法是沒毛病的,但是這里十分值得注意的是:該test()方法只能遍歷裝載著Object的集合!?。?/strong>

強(qiáng)調(diào):泛型中的并不是像以前那樣有繼承關(guān)系的,也就是說ListList是毫無關(guān)系的!?。?!

那現(xiàn)在咋辦???我們是不清楚List集合裝載的元素是什么類型的,List這樣是行不通的........于是Java泛型提供了類型通配符 ?

所以代碼應(yīng)該改成這樣:

public void test(List list){


    for(int i=0;i

?號通配符表示可以匹配任意類型,任意的Java類都可以匹配.....

現(xiàn)在非常值得注意的是,當(dāng)我們使用?號通配符的時候:就只能調(diào)對象與類型無關(guān)的方法,不能調(diào)用對象與類型有關(guān)的方法。

記住,只能調(diào)用與對象無關(guān)的方法,不能調(diào)用對象與類型有關(guān)的方法。因?yàn)橹钡酵饨缡褂貌胖谰唧w的類型是什么。也就是說,在上面的List集合,我是不能使用add()方法的。因?yàn)閍dd()方法是把對象丟進(jìn)集合中,而現(xiàn)在我是不知道對象的類型是什么。

3.4.1設(shè)定通配符上限

首先,我們來看一下設(shè)定通配符上限用在哪里....

現(xiàn)在,我想接收一個List集合,它只能操作數(shù)字類型的元素【Float、Integer、Double、Byte等數(shù)字類型都行】,怎么做???

我們學(xué)習(xí)了通配符,但是如果直接使用通配符的話,該集合就不是只能操作數(shù)字了。因此我們需要用到設(shè)定通配符上限

    List

上面的代碼表示的是:List集合裝載的元素只能是Number的子類或自身

    public static void main(String[] args) {


        //List集合裝載的是Integer,可以調(diào)用該方法
        List integer = new ArrayList<>();
        test(integer);

        //List集合裝載的是String,在編譯時期就報(bào)錯了
        List strings = new ArrayList<>();
        test(strings);

    }


    public static void test(List list) {
        
    }
3.4.2設(shè)定通配符下限

既然上面我們已經(jīng)說了如何設(shè)定通配符的上限,那么設(shè)定通配符的下限也不是陌生的事了。直接來看語法吧

    //傳遞進(jìn)來的只能是Type或Type的父類
    

設(shè)定通配符的下限這并不少見,在TreeSet集合中就有....我們來看一下

    public TreeSet(Comparator comparator) {
        this(new TreeMap<>(comparator));
    }

那它有什么用呢??我們來想一下,當(dāng)我們想要創(chuàng)建一個TreeSet類型的變量的時候,并傳入一個可以比較String大小的Comparator。

那么這個Comparator的選擇就有很多了,它可以是Comparator,還可以是類型參數(shù)是String的父類,比如說Comparator....

這樣做,就非常靈活了。也就是說,只要它能夠比較字符串大小,就行了

經(jīng)評論去補(bǔ)充:在泛型的上限和下限中有一個原則:PECS(Producer Extends Consumer Super)

書上是這樣寫的:

帶有子類限定的可以從泛型讀取【也就是--->(? extend T)】-------->Producer Extends
帶有超類限定的可以從泛型寫入【也就是--->(? super T)】-------->Consumer Super
也有相關(guān)博文寫得很好:

http://blog.51cto.com/flyingc...
https://blog.csdn.net/xx32666...

3.5通配符和泛型方法

大多時候,我們都可以使用泛型方法來代替通配符的.....

    //使用通配符
    public static void test(List list) {

    }

    //使用泛型方法
    public  void  test2(List t) {
        
    }

上面這兩個方法都是可以的.....那么現(xiàn)在問題來了,我們使用通配符還是使用泛型方法呢??

原則:

如果參數(shù)之間的類型有依賴關(guān)系,或者返回值是與參數(shù)之間有依賴關(guān)系的。那么就使用泛型方法

如果沒有依賴關(guān)系的,就使用通配符,通配符會靈活一些.

3.6泛型擦除

泛型是提供給javac編譯器使用的,它用于限定集合的輸入類型,讓編譯器在源代碼級別上,即擋住向集合中插入非法數(shù)據(jù)。但編譯器編譯完帶有泛形的java程序后,生成的class文件中將不再帶有泛形信息,以此使程序運(yùn)行效率不受到影響,這個過程稱之為“擦除”。

3.6.1兼容性

JDK5提出了泛型這個概念,但是JDK5以前是沒有泛型的。也就是泛型是需要兼容JDK5以下的集合的。

當(dāng)把帶有泛型特性的集合賦值給老版本的集合時候,會把泛型給擦除了。

值得注意的是:它保留的就類型參數(shù)的上限。

        List list = new ArrayList<>();

        //類型被擦除了,保留的是類型的上限,String的上限就是Object
        List list1 = list;

如果我把沒有類型參數(shù)的集合賦值給帶有類型參數(shù)的集合賦值,這又會怎么樣??

        List list = new ArrayList();
        List list2 = list;

它也不會報(bào)錯,僅僅是提示“未經(jīng)檢查的轉(zhuǎn)換”

四、泛型的應(yīng)用

當(dāng)我們寫網(wǎng)頁的時候,常常會有多個DAO,我們要寫每次都要寫好幾個DAO,這樣會有點(diǎn)麻煩。

那么我們想要的效果是什么呢??只寫一個抽象DAO,別的DAO只要繼承該抽象DAO,就有對應(yīng)的方法了。

要實(shí)現(xiàn)這樣的效果,肯定是要用到泛型的。因?yàn)樵诔橄驞AO中,是不可能知道哪一個DAO會繼承它自己,所以是不知道其具體的類型的。而泛型就是在創(chuàng)建的時候才指定其具體的類型。

抽象DAO


public abstract class BaseDao {

    //模擬hibernate....
    private Session session;
    private Class clazz;
    
    
    //哪個子類調(diào)的這個方法,得到的class就是子類處理的類型(非常重要)
    public BaseDao(){
        Class clazz = this.getClass();  //拿到的是子類
        ParameterizedType  pt = (ParameterizedType) clazz.getGenericSuperclass();  //BaseDao
        clazz = (Class) pt.getActualTypeArguments()[0];
        System.out.println(clazz);
        
    }
    

    public void add(T t){
        session.save(t);
    }
    
    public T find(String id){
        return (T) session.get(clazz, id);
    }
    
    public void update(T t){
        session.update(t);
    }
    
    public void delete(String id){
        T t = (T) session.get(clazz, id);
        session.delete(t);
    }
    
}

繼承抽象DAO,該實(shí)現(xiàn)類就有對應(yīng)的增刪改查的方法了。

CategoryDao

public class CategoryDao extends BaseDao {

}

BookDao

public class BookDao extends BaseDao {


}
五、最后

泛型的基礎(chǔ)就介紹到這里了,如果以后有需要的話再進(jìn)行深入研究吧~如果覺得該文章幫助到你,不妨點(diǎn)個贊,關(guān)注公眾號一波~

參考資料:

Core Java

如果文章有錯的地方歡迎指正,大家互相交流。習(xí)慣在微信看技術(shù)文章,想要獲取更多的Java資源的同學(xué),可以關(guān)注微信公眾號:Java3y

文章版權(quán)歸作者所有,未經(jīng)允許請勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請注明本文地址:http://systransis.cn/yun/68891.html

相關(guān)文章

  • 為vue3學(xué)點(diǎn)typescript, 泛型

    摘要:往期第一課體驗(yàn)第二課基礎(chǔ)類型和入門高級類型第三課泛型第四課解讀高級類型插一課本來打算接著上節(jié)課把高級類型都講完但是寫著寫著我發(fā)現(xiàn)高級類型中有很多地方都需要泛型的知識那么先插一節(jié)泛型什么是類型變量和泛型變量的概念我們都知道可以表示任意數(shù)據(jù)類型 往期 第一課, 體驗(yàn)typescript 第二課, 基礎(chǔ)類型和入門高級類型 第三課, 泛型 第四課, 解讀高級類型 插一課 本來打算接著上節(jié)課, ...

    tianlai 評論0 收藏0
  • Java3y文章目錄導(dǎo)航

    摘要:前言由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 前言 由于寫的文章已經(jīng)是有點(diǎn)多了,為了自己和大家的檢索方便,于是我就做了這么一個博客導(dǎo)航。 由于更新比較頻繁,因此隔一段時間才會更新目錄導(dǎo)航哦~想要獲取最新原創(chuàng)的技術(shù)文章歡迎關(guān)注我的公眾號:Java3y Java3y文章目錄導(dǎo)航 Java基礎(chǔ) 泛型就這么簡單 注解就這么簡單 Druid數(shù)據(jù)庫連接池...

    KevinYan 評論0 收藏0
  • Java 泛型總結(jié)(一):基本用法與類型擦除

    摘要:然而中的泛型使用了類型擦除,所以只是偽泛型。總結(jié)本文介紹了泛型的使用,以及類型擦除相關(guān)的問題。一般情況下泛型的使用比較簡單,但是某些情況下,尤其是自己編寫使用泛型的類或者方法時要注意類型擦除的問題。 簡介 Java 在 1.5 引入了泛型機(jī)制,泛型本質(zhì)是參數(shù)化類型,也就是說變量的類型是一個參數(shù),在使用時再指定為具體類型。泛型可以用于類、接口、方法,通過使用泛型可以使代碼更簡單、安全。然...

    Java_oldboy 評論0 收藏0
  • 教妹學(xué) Java:晦澀難懂的泛型

    摘要:首先,我們來按照泛型的標(biāo)準(zhǔn)重新設(shè)計(jì)一下類。注意參數(shù)為而不是泛型。利用形式的通配符,可以實(shí)現(xiàn)泛型的向上轉(zhuǎn)型,來看例子。需要注意的是,無法從這樣類型的中取出數(shù)據(jù)。showImg(https://user-gold-cdn.xitu.io/2019/5/17/16ac3bf3eb16160c); 00、故事的起源 二哥,要不我上大學(xué)的時候也學(xué)習(xí)編程吧?有一天,三妹突發(fā)奇想地問我。 你確定要做一名...

    Crazy_Coder 評論0 收藏0

發(fā)表評論

0條評論

最新活動
閱讀需要支付1元查看
<