Java 泛型,了解這些就夠用了。


 

此文目錄:

  1. Java泛型是什么?
  2. 通常的泛型的寫法示例
  3. 類型擦除
  4. 為什么要使用Java泛型
  5. 通過示例了解PECS原則

 

一、Java泛型是什么?

  • 官方定義
泛型是Java SE 1.5的新特性,泛型的本質是參數化類型,也就是說所操作的數據類型被指定為一個參數。
這種參數類型可以用在類、接口和方法的創建中,分別稱為泛型類、泛型接口、泛型方法。
  • 通俗解釋
通俗的講,泛型就是操作類型的 占位符,即:假設占位符為T,那么此次聲明的數據結構操作的數據類型為T類型。

 

二、通常的泛型寫法示例

  • T 類型,用於泛型類或者泛型方法

  泛型類定義:

public class ApiResult<T> {

int resultCode; String resultMsg; T resultObject;    // 省略構造方法和 get,set方法。 }

  定義泛型方法:

  

public class JsonUtil {
    
    public <T> T  str2Json(String jsonText,Class target){
        T result=null;
        //....parse to json 
        return result;
    }
}

 

 

  使用:

 

  //泛型類使用
ApiResult<User> result=new ApiResult<User>(); result.setResultCode(0); result.setResultMsg("success"); result.setResultObject(new User());

      ApiResult<List<User>> result2=new ApiResult<List<User>>();
      result.setResultCode(0);
      result.setResultMsg("success");
      result.setResultObject(userList);

 

      ApiResult<Integer> result3=new ApiResult<Integer>();
      result3.setResultCode(0);
      result3.setResultMsg("success");
      result3.setResultObject(99);

    //泛型方法使用

      String userJsonText="....省略",dogJsonText="....省略";;
          User u=JsonUtil.str2Json(jsonText,User.class);
          User u=JsonUtil.str2Json(jsonText,Dog.class);

  •  K,V類型,類似Map接口。

定義:

public class ResultMap<K,V> {

    private K key;
    private V value;
    
   //省略 set ,get  方法


public void put(K key,V value){ this.key=key; this.value=value; } }

使用:

        ResultMap<String,User> resultMap=new ResultMap<>();
        resultMap.put("currentUserKey", new User());
  • ?extends 類型
<? extends T> 表示類型的上界,表示參數化類型的可能是T 或是 T的子類
  • ?supper 類型
<? super T> 表示類型下界(Java Core中叫超類型限定),表示參數化類型是此類型的超類型(父類型),直至Object

  

 三、類型擦除

  先看一個例子,Operate類如下:

public class Operate {

    public static void main(String[] args) {

        List<String> names=new ArrayList<String>();
        names.add("Jack");
        names.add("Tom");
        names.add("peter");
        for(String name:names){
            System.out.println("wellcome:"+name);
        }
    }

}

其對應的class文件反編譯之后,我們使用java-gui反編譯.exe  查看編譯之后的代碼如下

發現沒有,根本沒有<String> 這一部分了。這個限制為String類型的泛型被“擦除”了。寫代碼的時候,泛型會做校驗,類型不對應的,無法add,但是編譯之后邊去掉了泛型類型。

 

  四、什么要使用Java泛型

 在上面 第三部分介紹了“類型擦除”之后,在來說為什么要使用Java泛型就比較好說了。這里的泛型就相當於“約法三章”,先給你定好“規矩”,我這個List<String> 就是用來操作

String類型的,你插入Person對象就不行。說白了就是為了類型安全。所以其好處有:

  類型安全:通過知道使用泛型定義的變量的類型限制,編譯器可以在一個高得多的程度上驗證類型假設。沒有泛型,這些假設就只存在於程序員的頭腦中(或者如果幸運的話,還存在於代碼注釋中)。

消除強制類型轉換:

//該代碼不使用泛型:
List li = new ArrayList();
li.put(new Integer(3));
Integer i = (Integer) li.get(0);


//該代碼使用泛型:
List<Integer> li = new ArrayList<Integer>();
li.put(new Integer(3));
Integer i = li.get(0);

 

 

了解了上面的這么多,已經足夠日常使用泛型了。下面了解下PECS原則

五、PECS原則

 

 先看例子:

此處定義三個類,spiring,summer繼承season
public
class Season { //..... } public class Spring extends Season { //...... } public class Summer extends Season { //....... }
        List<? extends Season> list1=new ArrayList<>();
        //list1.add(new Spring());//這里編譯不通過,因為編譯器無法確定list所持有的類型。
        List<? extends Season> list2=new ArrayList<Spring>(); // list2.add(new Spring());//也是無法通過編譯
    //通過上文,我們知道 ?extends Season表示可以接收的類型為 Seaon 或者其子類。
但是此處不行,因為可能傳入進來的是spring,或者summer,編譯器無法確定具體傳遞進來的是什么,
所以無法安全的向其中添加對象,但是它可以接收子類類型 的賦值。如下:
// List<Spring> list3=new ArrayList<Spring>(); List<? extends Season> list4=list3;//這里和上面的list2做對比,無法直接add spring類型的對象 //但是可以直接將spring類型的list賦值。 List<Season> seasons=new ArrayList<Season>(); List<? super Spring> spring=seasons; spring.add(new Spring());//ok // spring.add(new Summer());//error // spring.add(new Season());//error // spring.add(new Object());//error

 

        List<? super Season> sea=new ArrayList<>();
        sea.add(new Spring());//ok
        sea.add(new Summer());//ok
        sea.add(new Season());//ok
//        sea.add(new Object());//error
        
        List<? super Spring> spring=new ArrayList<>();
        spring.add(new Spring());//ok
//        spring.add(new Summer());//error
//        spring.add(new Season());//error
//        spring.add(new Object());//error

這里 ,PECS原則 如下:

如果要從集合中讀取類型T的數據,並且不能寫入,可以使用 ? extends 通配符;(Producer Extends)
如果要從集合中寫入類型T的數據,並且不需要讀取,可以使用 ? super 通配符;(Consumer Super)
如果既要存又要取,那么就不要使用任何通配符。

 

 

 

Java Queue系列之PriorityQueue

一篇圖看清Java中的各種Queue

 

[spring如何啟動的?這里結合spring源碼描述了啟動過程](https://www.cnblogs.com/demingblog/p/7443714.html)
[SpringMVC是怎么工作的,SpringMVC的工作原理](https://www.cnblogs.com/demingblog/p/9925268.html)
[spring 異常處理。結合spring源碼分析400異常處理流程及解決方法](https://www.cnblogs.com/demingblog/p/9218271.html)

[Mybatis Mapper接口是如何找到實現類的-源碼分析](https://www.cnblogs.com/demingblog/p/9544774.html)
[使用Netty實現HTTP服務器](https://www.cnblogs.com/demingblog/p/9970772.html)
[Netty實現心跳機制](https://www.cnblogs.com/demingblog/p/9957143.html)
[Netty系列](https://www.cnblogs.com/demingblog/p/9912099.html)

 

[Docker & k8s 系列一:快速上手docker](https://www.cnblogs.com/demingblog/p/12905545.html)
[Docker & k8s 系列二:本機k8s環境搭建](https://www.cnblogs.com/demingblog/p/12905563.html)
[Docker & k8s 系列三:在k8s中部署單個服務實例](https://www.cnblogs.com/demingblog/p/12905569.html)
[Docker & Kubenetes 系列四:集群,擴容,升級,回滾](https://www.cnblogs.com/demingblog/p/12919876.html)

 逃離沙漠公眾號


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM