Java:泛型

1. 泛型的概念

1.1 什么是泛型

泛型類似標(biāo)簽,出現(xiàn)原因是因?yàn)椋杭先萜黝愒谠O(shè)計(jì)階段/聲明階段不能確定這個(gè)容器到底實(shí)際存的是什么類型的對(duì)象

因此此時(shí)把元素的類型設(shè)計(jì)成一個(gè)參數(shù),這個(gè)類型參數(shù)叫做泛型

泛型,允許在定義類、接口時(shí)通過一個(gè)標(biāo)識(shí)表示類中某個(gè)屬性的類型或者是某個(gè)方法的返回值及參數(shù)類型

Collection<E>,List<E>,ArrayList<E> 這個(gè)<E>就是類型參數(shù),即泛型

1.2 泛型的好處

  1. 解決元素存儲(chǔ)的安全性問題,好比商品、藥品標(biāo)簽,不會(huì)弄錯(cuò)。
  2. 解決獲取數(shù)據(jù)元素時(shí),需要類型強(qiáng)制轉(zhuǎn)換的問題,好比不用每回拿商品、藥品都要辨別。

2. 集合中使用泛型

2.1 使用方法

  1. 集合接口或集合類在jdk5.e時(shí)都修改為帶泛型的結(jié)構(gòu)。
  2. 在實(shí)例化集合類時(shí),可以指明具體的泛型類型。
  3. 指明完以后,在集合類或接口中凡是定義類或接口時(shí),內(nèi)部結(jié)構(gòu)使用到類的泛型的位置,都指定為實(shí)例化的泛型類型。
  4. 注意點(diǎn):泛型的類型必須是類,不能是基本數(shù)據(jù)類型。需要用到基本數(shù)據(jù)類型的位置,拿包裝類替換。
  5. 如果實(shí)例化時(shí),沒有指明泛型的類型。默認(rèn)類型為java.Lang.Object類型。

2.2 具體舉例

以ArrayList為例

//導(dǎo)入的包有:import org.junit.Test;import java.util.*;

public class GenericTest {
    @Test
    public void test1(){
        ArrayList<Integer> list = new ArrayList<>();

        list.add(23);
        list.add(97);
        list.add(25);
        list.add(43);
        //編譯時(shí),就會(huì)進(jìn)行類型檢查,保證數(shù)據(jù)安全
//        list.add("Tom");

        //遍歷方式一:for
        for(Integer score : list){
            //避免了強(qiáng)轉(zhuǎn)操作
            int stuScore = score;
            System.out.println(stuScore);
        }

        //遍歷方式二:Iterator
        Iterator<Integer> iterator = list.iterator();
        while(iterator.hasNext()){
            int stuScore = iterator.next();
            System.out.println(stuScore);
        }

    }
}

以HashMap為例

//導(dǎo)入的包有:import org.junit.Test;import java.util.*;

public class GenericTest {
    @Test
    public void test2(){
        Map<String, Integer> map = new HashMap<String, Integer>();

        map.put("Tom",83);
        map.put("Jerry",77);
        map.put("Jack",33);

        //泛型的嵌套
        Set<Map.Entry<String, Integer>> entry = map.entrySet();
        Iterator<Map.Entry<String, Integer>> iterator = entry.iterator();
        //遍歷
        while(iterator.hasNext()){
            Map.Entry<String, Integer> e = iterator.next();
            String key = e.getKey();
            Integer value = e.getValue();
            System.out.println(key + ":" + value);
        }
    }
}

3. 自定義泛型結(jié)構(gòu)

3.1 泛型類與泛型接口

如何定義

泛型類與泛型接口的區(qū)別主要還是類與接口的區(qū)別,所以這里以泛型類舉例

public class Order<T> {
    String orderName;
    int orderId;

    //類的內(nèi)部結(jié)構(gòu)就可以使用泛型
    T orderT;

    public Order(){
    }
    public Order(String orderName,int orderId,T orderT){
        this.orderName = orderName;
        this.orderId = orderId;
        this.orderT = orderT;
    }
}

class Test{
    @org.junit.Test
    public void test1(){
        //要求:如果定義了類是帶泛型的,建議在實(shí)例化時(shí)使用它
        Order<String> order = new Order<String>("AA",1001,"hello");
    }
}

注意事項(xiàng)

  1. 泛型類可能有多個(gè)參數(shù),此時(shí)應(yīng)將多個(gè)參數(shù)一起放在尖括號(hào)內(nèi)。比如:<E1,E2,E3>
  2. 泛型類的構(gòu)造器如下:public GenericClass(){},而下面是錯(cuò)誤的:public GenericClass<E>(){}
  3. 實(shí)例化后,操作原來泛型位置的結(jié)構(gòu)必須與指定的泛型類型一致。
  4. 泛型不同的引用不能相互賦值。
  5. 泛型如果不指定,將被擦除,泛型對(duì)應(yīng)的類型均按照Object處理,但不等價(jià)于Object。
  6. 如果泛型結(jié)構(gòu)是一個(gè)接口或抽象類,則不可創(chuàng)建泛型類的對(duì)象。
  7. jdk1.7,泛型的簡(jiǎn)化操作:ArrayList<Fruit> flist = new ArrayList<>()。
  8. 泛型的指定中不能使用基本數(shù)據(jù)類型,可以使用包裝類替換。
  9. 在靜態(tài)方法中不能使用類的泛型。
  10. 異常類不能是泛型的。
  11. 不能使用new E[]。但是可以:E[] elements = (E[])new Object[capacity]。
  12. 父類有泛型,子類可以選擇保留泛型也可以選擇指定泛型類型:
    • 子類不保留父類的泛型:按需實(shí)現(xiàn)
      • 沒有類型,擦除
      • 具體類型
    • 子類保留父類的泛型:泛型子類
      • 全部保留
      • 部分保留

3.2 泛型方法

在方法中出現(xiàn)了泛型的結(jié)構(gòu),泛型參數(shù)與類的泛型參數(shù)沒有任何關(guān)系

也就是說,泛型方法所屬的類是不是泛型類都沒有關(guān)系

泛型參數(shù)在調(diào)用時(shí)體現(xiàn)泛型參數(shù)的類型

泛型方法可以是靜態(tài)的,是因?yàn)榉盒蛥?shù)是在調(diào)用方法時(shí)確定的

public <E> List<E> testMethod(E[] arr){
    
    ArrayList<E> list = new ArrayList<>();
    for(E e : arr){
        list.add(e);
    }
    return list;
}

4. 泛型在繼承上的體現(xiàn)

若子類在繼承帶泛型的父類時(shí),指明了泛型類型,則實(shí)例化子類對(duì)象時(shí),不再需要指明泛型。

若子類在繼承帶泛型的父類時(shí),沒有指明了泛型類型,則實(shí)例化子類對(duì)象時(shí),需要指明泛型。

若類A是類B的父類,但G<A>和G<B>二者不具備子父類關(guān)系,二者是并列關(guān)系

若類A是類B的父類,A<G>是B<G>的父類

5. 通配符的使用

5.1 通配符的概念

通配符的符號(hào)是"?",它的使用方法為使用"?"代替具體的類型參數(shù)

例如:類A是類B的父類,G<A>和G<B>是沒有關(guān)系的,但二者共同的父類是G<?>

//導(dǎo)入的包:import org.junit.Test;import java.util.List;

public class TongPeiFu {
    @Test
    public void test1(){
        List<Object> list1 = null;
        List<Object> list2 = null;

        List<?> list = null;

        list = list1;
        list = list2;
    }
}

5.2 通配符的寫入與讀取

對(duì)于List<?>不能向其內(nèi)部添加數(shù)據(jù),因?yàn)椴恢榔渥宇愄砑拥氖鞘裁磾?shù)據(jù)

對(duì)于List<?>允許讀取數(shù)據(jù),讀取數(shù)據(jù)類型為Object

//導(dǎo)入的包有:import org.junit.Test;import java.util.ArrayList;import java.util.List;

public class TongPeiFu {
    @Test
    public void test2(){
        List<String> list3 = new ArrayList<>();
        list3.add("AA");
        list3.add("BB");
        list3.add("CC");

        List<?> list = list3;
        
        //添加:對(duì)于List<?>不能向其內(nèi)部添加數(shù)據(jù)
        //除了添加null之外
        list.add(null);

        //獲?。涸试S讀取數(shù)據(jù),讀取數(shù)據(jù)類型為Object
        Object o = list.get(0);
        System.out.println(o);//AA
    }
}

5.3 有限制的通配符

  1. G<? extends A>:可以作為G<A>和G<B>的父類,其中B是A的子類
  2. G<? super A>:可以作為G<A>和G<B>的父類,其中B是A的父類
//導(dǎo)入的包有:import org.junit.Test;import java.util.ArrayList;import java.util.List;

public class TongPeiFu {
    @Test
    public void test2(){
        List<? extends Person> list1 = null;
        List<? super person> list2 = null;

        List<Student> list3 = null;
        List<Person> list4 = null;
        List<Object> list5 = null;

        //G<? extends A>可以作為包括A以下類的父類
        list1 = list3;
        list1 = list4;
//        list1 = list5;

        //G<? super A>可以作為包括A以上類的父類
//        list2 = list3;
        list2 = list4;
        list2 = list5;
    }
}

?著作權(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)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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