美滋滋!教會(huì)了公司小姐姐Java中泛型如何使用,她現(xiàn)在要加我微信了!

一、什么是泛型?

1.泛型是一種未知的數(shù)據(jù)類型,當(dāng)我們不知道使用什么數(shù)據(jù)類型的時(shí)候,可以使用泛型。
2.泛型也可以看作是一個(gè)變量,用來(lái)接收數(shù)據(jù)類型(注意接收的是數(shù)據(jù)類型)。

E e:Element 元素
T t:Type 類型

例如:ArrayList集合在定義的時(shí)候,不知道集合中都會(huì)存儲(chǔ)什么類型的數(shù)據(jù),所以類型使用泛型。

public class ArrayList<E> {
    public boolean add(E e) {}
    public E get(int index){}
}

創(chuàng)建集合對(duì)象的時(shí)候,就會(huì)確定泛型的數(shù)據(jù)類型


二、泛型的好處

創(chuàng)建集合對(duì)象,使用泛型

好處:

  1. 避免了類型轉(zhuǎn)換的麻煩,存儲(chǔ)的是什么類型,取出的就是什么類型;
  2. 把運(yùn)行期異常(代碼運(yùn)行之后會(huì)拋出的異常),提升到了編譯期(寫(xiě)代碼的時(shí)候會(huì)報(bào)錯(cuò));

弊端:

  1. 泛型是什么類型,只能存儲(chǔ)什么類型的數(shù)據(jù);
    private static void show01() {
        ArrayList<String> list = new ArrayList<>();
        list.add("abc");
        list.add(1);//報(bào)錯(cuò):add(java.lang.String)in ArrayList cannot be applied to (int)

        //使用迭代器遍歷list集合
        Iterator<String> it = list.iterator();
        while(it.hasNext()){
            String s = it.next();
            System.out.println(s+"->"+s.length());
        }
    }

創(chuàng)建集合對(duì)象,不使用泛型

好處: 集合不使用泛型,默認(rèn)的類型就是Object類型,可以存儲(chǔ)任意類型的數(shù)據(jù);

弊端: 不安全,會(huì)引發(fā)異常;

    private static void show02() {
        ArrayList list = new ArrayList();
        list.add("abc");
        list.add(1);

        //使用迭代器遍歷list集合
        //獲取迭代器
        Iterator it = list.iterator();
        //使用迭代器中的方法hasNext和next遍歷集合
        while(it.hasNext()){
            //取出元素也是Object類型
            Object obj = it.next();
            System.out.println(obj);

            //想要使用String類特有的方法,length獲取字符串的長(zhǎng)度;不能使用  多態(tài) Object obj = "abc";
            //需要向下轉(zhuǎn)型
            //會(huì)拋出ClassCastException類型轉(zhuǎn)換異常,不能把Integer類型轉(zhuǎn)換為String類型
            String s = (String)obj;
            System.out.println(s.length());
        }
    }

三、泛型的定義與使用

1.定義使用含有泛型的類

/**
    定義一個(gè)含有泛型的類,模擬ArrayList集合
    泛型是一個(gè)未知的數(shù)據(jù)類型,當(dāng)我們不確定什么什么數(shù)據(jù)類型的時(shí)候,可以使用泛型
    泛型可以接收任意的數(shù)據(jù)類型,可以使用Integer,String,對(duì)象Student...
    創(chuàng)建對(duì)象的時(shí)候確定泛型的數(shù)據(jù)類型
 */
public class GenericClass<E>{
    private E name;

    public E getName() {
        return name;
    }

    public void setName(E name) {
        this.name = name;
    }
}

使用該類

public class DemoGenericClass {

    public static void main(String[] args) {
        //不寫(xiě)泛型默認(rèn)為Object類型
        GenericClass gc = new GenericClass();
        gc.setName("只能是字符串");
        Object obj = gc.getName();
        System.out.println(obj);

        GenericClass<Integer> gc2 = new GenericClass<>();
        gc2.setName(1);

        Integer name1 = gc2.getName();
        System.out.println(name1);

        //創(chuàng)建GenericClass對(duì)象,泛型使用String類型
        GenericClass<String> gc3 = new GenericClass<>();
        gc3.setName("小明");
        String name2 = gc3.getName();
        System.out.println(name2);
    }

}

2.定義和使用含有泛型的方法

泛型定義在方法的修飾符和返回值類型之間

格式:
修飾符 <泛型> 返回值類型 方法名(泛型 參數(shù)名){
? 方法體;
}
含有泛型的方法,在調(diào)用方法的時(shí)候確定泛型的數(shù)據(jù)類型
傳遞什么類型的參數(shù),泛型就是什么類型

public class GenericMethod {

    //定義一個(gè)含有泛型的方法
    public <M> void method01(M m) {
        System.out.println(m);
    }

    //定義一個(gè)含有泛型的靜態(tài)方法
    public static <S> void method02(S s){
        System.out.println(s);
    }

    //返回值泛型
    public <T> T method03(T t) {
        return t;
    }
}

使用該類

public class DemoGenericMethod {
    public static void main(String[] args) {
        //創(chuàng)建GenericMethod對(duì)象
        GenericMethod gm = new GenericMethod();

        /*
            調(diào)用含有泛型的方法method01
            傳遞什么類型,泛型就是什么類型
        */
        gm.method01(10);
        gm.method01("abc");
        gm.method01(8.8);
        gm.method01(true);

        //靜態(tài)方法,通過(guò)類名.方法名(參數(shù))可以直接使用
        GenericMethod.method02("靜態(tài)方法");
        GenericMethod.method02(1);

        ///泛型返回值
        String s = gm.method03("aaa");
        System.out.println(s);
    }
}

3.定義和使用含有泛型的接口

/**
 * 定義含有泛型的接口
 */
public interface GenericInterface<I> {

    public abstract void method(I i);
}

含有泛型的接口第一種使用方式:定義接口的實(shí)現(xiàn)類,實(shí)現(xiàn)接口,指定接口的泛型

public class GenericInterfaceImpl1 implements GenericInterface<String> {
    @Override
    public void method(String s) {
        System.out.println(s);
    }
}

public class DemoGenericInterface {
    public static void main(String[] args) {
        //創(chuàng)建GenericInterfaceImpl1對(duì)象
        GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
        gi1.method("字符串");
    }
}

含有泛型的接口第二種使用方式:接口使用什么泛型,實(shí)現(xiàn)類就使用什么泛型,類跟著接口走

/**
 *     含有泛型的接口第二種使用方式:接口使用什么泛型,實(shí)現(xiàn)類就使用什么泛型,類跟著接口走
 *     就相當(dāng)于定義了一個(gè)含有泛型的類,創(chuàng)建對(duì)象的時(shí)候確定泛型的類型
 *     public interface List<E>{
 *         boolean add(E e);
 *         E get(int index);
 *     }
 *     public class ArrayList<E> implements List<E>{
 *         public boolean add(E e) {}
 *         public E get(int index) {}
 *     }
 */
public class GenericInterfaceImpl2<I> implements GenericInterface<I>{
    @Override
    public void method(I i) {
        System.out.println(i);
    }
}

public class DemoGenericInterface {
    public static void main(String[] args) {
        //創(chuàng)建GenericInterfaceImpl2對(duì)象
        GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
        gi2.method(10);

        GenericInterfaceImpl2<Double> gi3 = new GenericInterfaceImpl2<>();
        gi3.method(8.8);
    }
}

四、泛型通配符

1.泛型通配符的使用

當(dāng)使用泛型類或者接口時(shí),傳遞的數(shù)據(jù)中,泛型不確定,可以通過(guò)通配符 < ? > 表示。但是一旦使用泛型通配符后,只能使用Object類中的共性方法,集合中元素自身的方法無(wú)法使用。

泛型的通配符:
??:代表任意的數(shù)據(jù)類型
使用方式:
?1.不能創(chuàng)建對(duì)象使用
?2.只能作為方法的參數(shù)使用

/**
 *     泛型的通配符:
 *         ?:代表任意的數(shù)據(jù)類型
 *     使用方式:
 *         不能創(chuàng)建對(duì)象使用
 *         只能作為方法的參數(shù)使用
 */
public class DemoGeneric {

    public static void main(String[] args) {
        ArrayList<Integer> list01 = new ArrayList<>();
        list01.add(1);
        list01.add(2);

        ArrayList<String> list02 = new ArrayList<>();
        list02.add("a");
        list02.add("b");

        printArray(list01);
        printArray(list02);

        //ArrayList<?> list03 = new ArrayList<?>();//報(bào)錯(cuò):不能創(chuàng)建對(duì)象使用
    }

    /**
     *         定義一個(gè)方法,能遍歷所有類型的ArrayList集合
     *         這時(shí)候我們不知道ArrayList集合使用什么數(shù)據(jù)類型,可以泛型的通配符?來(lái)接收數(shù)據(jù)類型
     *         注意:
     *             泛型沒(méi)有繼承概念的
     * @param list
     */
    public static void printArray(ArrayList<?> list) {
        Iterator<?> it = list.iterator();
        while (it.hasNext()) {
            //it.next()方法,取出的元素是Object,可以接收任意的數(shù)據(jù)類型
            Object o = it.next();
            System.out.println(o);
        }
    }
}

2.泛型通配符的高級(jí)使用----受限泛型

之前設(shè)置泛型的時(shí)候,實(shí)際上可以是任意設(shè)置的,只要是類就可以設(shè)置。但是在Java中泛型可以指定一個(gè)泛型的上限下限。

泛型的上限

  • 格式:類型名稱 <? extends 類 > 對(duì)象名稱
  • 意義:只接收該類型及其子類

泛型的下限

  • 格式:類型名稱 <? super 類 > 對(duì)象名稱
  • 意義:只接收該類型及其父類
/*
    泛型的上限限定: ? extends E  代表使用的泛型只能是E類型的子類/本身
    泛型的下限限定: ? super E    代表使用的泛型只能是E類型的父類/本身
 */
public class Demo06Generic {
    public static void main(String[] args) {
        Collection<Integer> list1 = new ArrayList<Integer>();
        Collection<String> list2 = new ArrayList<String>();
        Collection<Number> list3 = new ArrayList<Number>();
        Collection<Object> list4 = new ArrayList<Object>();

        getElement1(list1);
        //getElement1(list2);//報(bào)錯(cuò)
        getElement1(list3);
        //getElement1(list4);//報(bào)錯(cuò)

        //getElement2(list1);//報(bào)錯(cuò)
        //getElement2(list2);//報(bào)錯(cuò)
        getElement2(list3);
        getElement2(list4);

        /*
            類與類之間的繼承關(guān)系
            Integer extends Number extends Object
            String extends Object
         */

    }
    // 泛型的上限:此時(shí)的泛型?,必須是Number類型或者Number類型的子類
    public static void getElement1(Collection<? extends Number> coll){}
    // 泛型的下限:此時(shí)的泛型?,必須是Number類型或者Number類型的父類
    public static void getElement2(Collection<? super Number> coll){}
}

以上是我的整理,希望能幫助大家,謝謝。

最后

歡迎關(guān)注公眾號(hào):前程有光,領(lǐng)取一線大廠Java面試題總結(jié)+各知識(shí)點(diǎn)學(xué)習(xí)思維導(dǎo)+一份300頁(yè)pdf文檔的Java核心知識(shí)點(diǎn)總結(jié)! 這些資料的內(nèi)容都是面試時(shí)面試官必問(wèn)的知識(shí)點(diǎn),篇章包括了很多知識(shí)點(diǎn),其中包括了有基礎(chǔ)知識(shí)、Java集合、JVM、多線程并發(fā)、spring原理、微服務(wù)、Netty 與RPC 、Kafka、日記、設(shè)計(jì)模式、Java算法、數(shù)據(jù)庫(kù)、Zookeeper、分布式緩存、數(shù)據(jù)結(jié)構(gòu)等等。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • @[toc] 1.泛型概述 在Thinking in java 第五版的第二十章中,開(kāi)篇說(shuō)到,在普通的類和方法中只...
    冬天里的懶喵閱讀 1,188評(píng)論 0 0
  • 泛型 1.為什么要有泛型(存在的意義) 對(duì)于集合,他可以存儲(chǔ)各種類型的對(duì)象,正因?yàn)樗某橄螅瑢?dǎo)致使用時(shí)會(huì)出現(xiàn)混亂 ...
    controler閱讀 213評(píng)論 0 0
  • 概述 泛型的本質(zhì)是參數(shù)化類型,通常用于輸入?yún)?shù)、存儲(chǔ)類型不確定的場(chǎng)景。相比于直接使用 Object 的好處是:編譯...
    彳亍口巴閱讀 180評(píng)論 0 3
  • 什么是泛型 Java泛型( generics) 是JDK 5中引?的?個(gè)新特性, 允許在定義類和接口的時(shí)候使?類型...
    西界__閱讀 323評(píng)論 0 1
  • 夜鶯2517閱讀 128,095評(píng)論 1 9

友情鏈接更多精彩內(nèi)容