<kbd id="5sdj3"></kbd>
<th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>

    Java泛型詳解,通俗易懂只需5分鐘

    共 4727字,需瀏覽 10分鐘

     ·

    2022-01-13 16:49

    點(diǎn)擊關(guān)注公眾號(hào),Java干貨及時(shí)送達(dá)

    Java術(shù)?|?

    從Java1.5開(kāi)始,官方引入了泛型機(jī)制,事實(shí)上,從1.3版本開(kāi)始,泛型就已經(jīng)存在了,經(jīng)過(guò)歷代的發(fā)展,已足具雛形,本篇文章就來(lái)學(xué)習(xí)一下泛型的使用。


    01

    認(rèn)識(shí)泛型


    在此之前,我們先來(lái)認(rèn)識(shí)一下泛型吧,先看一段示例:

    public class Main {

    public static void main(String[] args) {
    List list = new ArrayList();
    list.add(1);
    list.add(2);
    list.add(3);
    dealList(list);
    }

    public static void dealList(List list) {
    int result = 0;
    for (Object obj : list) {
    int num = (int) obj;
    result += num;
    }
    System.out.println(result);
    }
    }

    在該示例中,dealList方法用于計(jì)算一個(gè)集合中的元素和,當(dāng)然,只有數(shù)字才能夠參與運(yùn)算,但是示例中的list是可以存放任意對(duì)象的,所以很可能會(huì)出現(xiàn)如下情況:

    public static void main(String[] args) {
    List list = new ArrayList();
    list.add(1);
    list.add(2);
    list.add(3);
    list.add("4");
    dealList(list);
    }

    因?yàn)樽址疅o(wú)法轉(zhuǎn)為整型,所以程序會(huì)報(bào)錯(cuò):

    Exception in thread "main" java.lang.ClassCastException: java.lang.String cannot be cast to java.lang.Integer

    這時(shí)候泛型的約束就顯得尤為重要,在定義集合的時(shí)候?qū)ζ溥M(jìn)行類型的限定即可在編譯期就避免這一類問(wèn)題:


    02

    定義泛型類


    泛型的用法十分多樣,它可以作用在類、方法上實(shí)現(xiàn)各種功能,先來(lái)了解一下泛型類的定義。

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Genericity {

    private String str1;
    private String str2;
    }

    以上是一個(gè)簡(jiǎn)單的Java類,我們想通過(guò)它計(jì)算其中兩個(gè)屬性值的和:

    public static void main(String[] args) {
    Genericity genericity = new Genericity("1","1");
    String str1 = genericity.getStr1();
    String str2 = genericity.getStr2();
    Integer num1 = Integer.valueOf(str1);
    Integer num2 = Integer.valueOf(str2);
    int result = num1 + num2;
    System.out.println(result);
    }

    但此時(shí)我覺(jué)得將屬性定義為String是一個(gè)錯(cuò)誤的決定,因?yàn)橛?jì)算屬性值的和還需要自己對(duì)類型進(jìn)行轉(zhuǎn)換,所以我將屬性調(diào)整為了Integer類型:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Genericity {

    private Integer str1;
    private Integer str2;
    }

    當(dāng)然了,這個(gè)例子可能有一些牽強(qiáng),事實(shí)上不會(huì)有人這么做,但目的很明顯,就是想讓類中的屬性類型可變,使得整個(gè)類更加靈活,基于此需求,我們可以使用泛型對(duì)其進(jìn)行改造:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class Genericity {

    private T t1;
    private T t2;
    }

    這就是泛型類的定義,通過(guò)在類名后面添加符號(hào)即可定義泛型類,而類中的屬性類型均為T,這將導(dǎo)致類中的屬性類型會(huì)跟隨T的變化而變化,用法如下:

    public static void main(String[] args) {
    Genericity<Integer> genericity = new Genericity<>(1, 1);
    Integer t1 = genericity.getT1();
    Integer t2 = genericity.getT2();
    int result = t1 + t2;
    System.out.println(result);
    }

    在創(chuàng)建泛型類對(duì)象時(shí),同樣在類名后添加,此時(shí)Integer就作為了T符合的內(nèi)容,所以類中的屬性都將是Integer類型。如果類名后添加,則類中的屬性均為String類型。

    實(shí)際上,泛型類可以定義多個(gè)泛型變量,比如:

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class GenericityU> {

    private T t1;
    private U t2;
    }

    此時(shí)我們?cè)趧?chuàng)建對(duì)象時(shí)就可以傳入兩個(gè)類型:

    public static void main(String[] args) {
    GenericityString> genericity = new Genericity<>(1, "1");
    Integer t1 = genericity.getT1();
    String t2 = genericity.getT2();
    }


    03

    定義泛型方法


    泛型除了作用在類上,還可以作用在方法上,效果與泛型類是相似的。

    public static  void method(T t) {
    }

    只需在調(diào)用方法時(shí)傳入類型即可:

    public static void main(String[] args) {
    Genericity.<Integer>method(1);
    }

    而事實(shí)上,你無(wú)需這么寫,因?yàn)榫幾g器能夠自動(dòng)推斷出泛型類型T,所以調(diào)用泛型方法可以簡(jiǎn)寫為:

    public static void main(String[] args) {
    Genericity.method(1);
    }

    泛型方法的返回值也可以使用類型變量:

    public static  T method(T t) {
    return t;
    }

    當(dāng)然了,泛型方法也支持定義多個(gè)類型變量:

    public static  T method(T t,U u) {
    return t;
    }


    04

    泛型的限定符


    來(lái)看下面的程序:

    public static  T min(T[] t) {
    T minimum = t[0];
    for (int i = 0; i < t.length; i++) {
    if (minimum.compareTo(t[i]) > 0) {
    minimum = t[i];
    }
    }
    return minimum;
    }

    能看得出來(lái)這段程序在干什么嗎?是的,它能夠取出數(shù)組t中的最小值,然而這段程序是有問(wèn)題的,因?yàn)門可以是任意類型的對(duì)象,但不是什么對(duì)象都能夠調(diào)用compareTo方法進(jìn)行比較的,所以,我們需要對(duì)類型變量T進(jìn)行限定,限定為實(shí)現(xiàn)了Comparable接口的對(duì)象,如下:

    public static  T min(T[] t) {
    T minimum = t[0];
    for (int i = 0; i < t.length; i++) {
    if (minimum.compareTo(t[i]) > 0) {
    minimum = t[i];
    }
    }
    return minimum;
    }

    一個(gè)泛型方法也可以對(duì)類型變量進(jìn)行多個(gè)限定:

    public static  T min(T[] t) {
    ......
    }


    05

    泛型擦除


    需要知道的是,泛型僅僅是在編譯期間起作用,目的是讓程序員在編譯期間就避免發(fā)生一些類型不對(duì)應(yīng)的問(wèn)題,而在運(yùn)行階段,泛型是根本不存在的,因?yàn)樘摂M機(jī)會(huì)對(duì)泛型進(jìn)行擦除。

    我們可以通過(guò)反射進(jìn)行驗(yàn)證,因?yàn)榉瓷涫亲饔迷谶\(yùn)行階段的:

    public static void main(String[] args) throws Exception {
    List list = new ArrayList<>();
    list.add(1);
    Method addMethod = list.getClass().getDeclaredMethod("add",Object.class);
    addMethod.invoke(list,"2");
    addMethod.invoke(list,true);
    addMethod.invoke(list,3.2f);
    System.out.println(list);
    }

    若是通過(guò)反射能夠?qū)⑦@些非Integer類型的值存入list,則說(shuō)明在運(yùn)行期間確實(shí)是不存在泛型檢查的,運(yùn)行結(jié)果如下:

    [1, 2, true, 3.2]

    泛型擦除也體現(xiàn)在泛型方法中,回顧之前的例子:

    public static  T min(T[] t) {
    ......
    }

    當(dāng)程序運(yùn)行期間,泛型會(huì)被擦除,此時(shí)方法變?yōu)槿缦拢?/p>

    public static Comparable min(Comparable t) {
    ......
    }

    這也就是為什么類型限定能夠生效的原因了,通過(guò)泛型擦除后,該方法就只能接收和返回Comparable接口的實(shí)現(xiàn)類。



    06

    泛型通配符


    固定的泛型類型顯然無(wú)法滿足復(fù)雜多變的需求,為此,泛型設(shè)計(jì)者們還提供了泛型通配符,如:

    Genericity extends Person>

    它表示類型變量必須是Person類型的子類。當(dāng)然了,泛型通配符還有超類型定義的情況:

    Genericitysuper Person>

    此時(shí)類型變量就必須是Person類的超類。

    還有一種情況是無(wú)限定通配符:

    Genericity>

    它和Genericity非常相似,但又有不同,Genericity的setter方法不能被調(diào)用,getter方法只能返回Object類型,不過(guò)這種方式的用法較少,可能會(huì)被用來(lái)判斷空引用:

    public static boolean isNull(Genericity genericity){
    return genericity.getContent();
    }

    本文作者:汪偉俊?為Java技術(shù)迷專欄作者?投稿,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載


    1、致歉!抖音Semi Design承認(rèn)參考阿里Ant Design

    2、對(duì)比7種分布式事務(wù)方案,還是偏愛(ài)阿里開(kāi)源的Seata,真香!

    3、Redis存儲(chǔ)結(jié)構(gòu)體信息,選hash還是string?

    4、掃盲 docker 常用命令

    5、最全分布式Session解決方案

    6、21 款 yyds 的 IDEA插件

    7、真香!用 IDEA 神器看源碼,效率真高!

    點(diǎn)分享

    點(diǎn)收藏

    點(diǎn)點(diǎn)贊

    點(diǎn)在看

    瀏覽 40
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)
    評(píng)論
    圖片
    表情
    推薦
    點(diǎn)贊
    評(píng)論
    收藏
    分享

    手機(jī)掃一掃分享

    分享
    舉報(bào)

    <kbd id="5sdj3"></kbd>
    <th id="5sdj3"></th>

  • <dd id="5sdj3"><form id="5sdj3"></form></dd>
    <td id="5sdj3"><form id="5sdj3"><big id="5sdj3"></big></form></td><del id="5sdj3"></del>

  • <dd id="5sdj3"></dd>
    <dfn id="5sdj3"></dfn>
  • <th id="5sdj3"></th>
    <tfoot id="5sdj3"><menuitem id="5sdj3"></menuitem></tfoot>

  • <td id="5sdj3"><form id="5sdj3"><menu id="5sdj3"></menu></form></td>
  • <kbd id="5sdj3"><form id="5sdj3"></form></kbd>
    亚洲欧美精品AAAAAA片 | 精品av国产日韩一区二区 | 久久久亚洲AV无码日韩精品 | 亚洲AV无码秘 蜜桃渚光希 | 男女日在线看 |