1. 程式人生 > 其它 >美滋滋!教會了公司小姐姐Java中泛型如何使用,她現在要加我微信了!

美滋滋!教會了公司小姐姐Java中泛型如何使用,她現在要加我微信了!

一、什麼是泛型?

1.泛型是一種未知的資料型別,當我們不知道使用什麼資料型別的時候,可以使用泛型。 2.泛型也可以看作是一個變數,用來接收資料型別(注意接收的是資料型別)。

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

複製程式碼

例如:ArrayList集合在定義的時候,不知道集合中都會儲存什麼型別的資料,所以型別使用泛型。

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

複製程式碼

建立集合物件的時候,就會確定泛型的資料型別

二、泛型的好處

建立集合物件,使用泛型

好處:

  1. 避免了型別轉換的麻煩,儲存的是什麼型別,取出的就是什麼型別;
  2. 把執行期異常(程式碼執行之後會丟擲的異常),提升到了編譯期(寫程式碼的時候會報錯);

弊端:

  1. 泛型是什麼型別,只能儲存什麼型別的資料;
    private static void show01() {
        ArrayList<String> list = new ArrayList<>();
        list.add("abc");
        list.add(1);//報錯: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());
        }
    }

複製程式碼

建立集合物件,不使用泛型

好處:集合不使用泛型,預設的型別就是Object型別,可以儲存任意型別的資料;

弊端:不安全,會引發異常;

    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獲取字串的長度;不能使用  多型 Object obj = "abc";
            //需要向下轉型
            //會丟擲ClassCastException型別轉換異常,不能把Integer型別轉換為String型別
            String s = (String)obj;
            System.out.println(s.length());
        }
    }

複製程式碼

三、泛型的定義與使用

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

/**
    定義一個含有泛型的類,模擬ArrayList集合
    泛型是一個未知的資料型別,當我們不確定什麼什麼資料型別的時候,可以使用泛型
    泛型可以接收任意的資料型別,可以使用Integer,String,物件Student...
    建立物件的時候確定泛型的資料型別
 */
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) {
        //不寫泛型預設為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);

        //建立GenericClass物件,泛型使用String型別
        GenericClass<String> gc3 = new GenericClass<>();
        gc3.setName("小明");
        String name2 = gc3.getName();
        System.out.println(name2);
    }

}

複製程式碼

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

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

格式: 修飾符 <泛型> 返回值型別 方法名(泛型 引數名){   方法體; } 含有泛型的方法,在呼叫方法的時候確定泛型的資料型別 傳遞什麼型別的引數,泛型就是什麼型別

public class GenericMethod {

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

    //定義一個含有泛型的靜態方法
    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) {
        //建立GenericMethod物件
        GenericMethod gm = new GenericMethod();

        /*
            呼叫含有泛型的方法method01
            傳遞什麼型別,泛型就是什麼型別
        */
        gm.method01(10);
        gm.method01("abc");
        gm.method01(8.8);
        gm.method01(true);

        //靜態方法,通過類名.方法名(引數)可以直接使用
        GenericMethod.method02("靜態方法");
        GenericMethod.method02(1);

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

複製程式碼

3.定義和使用含有泛型的介面

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

    public abstract void method(I i);
}

複製程式碼

含有泛型的介面第一種使用方式:定義介面的實現類,實現介面,指定介面的泛型

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) {
        //建立GenericInterfaceImpl1物件
        GenericInterfaceImpl1 gi1 = new GenericInterfaceImpl1();
        gi1.method("字串");
    }
}

複製程式碼

含有泛型的介面第二種使用方式:介面使用什麼泛型,實現類就使用什麼泛型,類跟著介面走

/**
 *     含有泛型的介面第二種使用方式:介面使用什麼泛型,實現類就使用什麼泛型,類跟著介面走
 *     就相當於定義了一個含有泛型的類,建立物件的時候確定泛型的型別
 *     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) {
        //建立GenericInterfaceImpl2物件
        GenericInterfaceImpl2<Integer> gi2 = new GenericInterfaceImpl2<>();
        gi2.method(10);

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

複製程式碼

四、泛型萬用字元

1.泛型萬用字元的使用

當使用泛型類或者介面時,傳遞的資料中,泛型不確定,可以通過萬用字元 < ? > 表示。但是一旦使用泛型萬用字元後,只能使用Object類中的共性方法,集合中元素自身的方法無法使用。

泛型的萬用字元:  ?:代表任意的資料型別 使用方式:  1.不能建立物件使用  2.只能作為方法的引數使用

/**
 *     泛型的萬用字元:
 *         ?:代表任意的資料型別
 *     使用方式:
 *         不能建立物件使用
 *         只能作為方法的引數使用
 */
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<?>();//報錯:不能建立物件使用
    }

    /**
     *         定義一個方法,能遍歷所有型別的ArrayList集合
     *         這時候我們不知道ArrayList集合使用什麼資料型別,可以泛型的萬用字元?來接收資料型別
     *         注意:
     *             泛型沒有繼承概念的
     * @param list
     */
    public static void printArray(ArrayList<?> list) {
        Iterator<?> it = list.iterator();
        while (it.hasNext()) {
            //it.next()方法,取出的元素是Object,可以接收任意的資料型別
            Object o = it.next();
            System.out.println(o);
        }
    }
}

複製程式碼

2.泛型萬用字元的高階使用----受限泛型

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

泛型的上限

  • 格式:型別名稱 <? extends 類 > 物件名稱
  • 意義:只接收該型別及其子類

泛型的下限

  • 格式:型別名稱 <? super 類 > 物件名稱
  • 意義:只接收該型別及其父類
/*
    泛型的上限限定: ? 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);//報錯
        getElement1(list3);
        //getElement1(list4);//報錯

        //getElement2(list1);//報錯
        //getElement2(list2);//報錯
        getElement2(list3);
        getElement2(list4);

        /*
            類與類之間的繼承關係
            Integer extends Number extends Object
            String extends Object
         */

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

複製程式碼

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


作者:前程有光
連結:https://juejin.cn/post/6932061799520927758