1. 程式人生 > >對Java萬用字元的個人理解(以集合為例)

對Java萬用字元的個人理解(以集合為例)

二、泛型萬用字元講解

 <一>萬用字元的使用以及程式碼演示

      1.無限萬用字元<?>的使用:可以傳入任何引用資料型別

A 在呼叫方法時使用?萬用字元的過程中無法使用add方法。

原因分析:因為萬用字元?代表任意的資料型別,但是當我們呼叫的時候或者用在方法的宣告上,其實這個時候還是沒有給?萬用字元一個指定的引用資料型別,那麼Java出於安全起見,就不可能允許新增元素。


B 以上的add方法雖然無法呼叫,add<null>是例外。

原因分析:因為null可以給任意引用資料型別賦值,代表任意引用資料,但是很容易引起NullPointerException。


C 注意使用List<?>和List<Object>當作形參時的作用不能等同,比如當傳入List<Integer>時List<?>可以接收,但是List<Object>無法接收。

原因分析:因為?代表任何引數型別可以接收,但是List<Object>中雖然Object是所有子類的父類,但是List<Object>不是List<Integer>的父類,List<Object>是ArrayList<Object>等類的父類,這就是為什麼泛型前後要一致的原因,從陣列的角度去理解集合就比如Object[ ] arr不是Integer[ ] arr1的父類。

 1 public class WildCardTest<E> {
 2 
 3     public static void main(String[] args) {
 4 //      ArrayList<Object> list2 = new ArrayList<Integer>();//泛型前後一致
 5         ArrayList<?> list = new ArrayList<String>();
 6 //      list.add("122");//注意此處無法新增"122"字串,但是可以新增null,因為null可以給任何引用資料型別賦值
7 list.add(null);//新增null沒有報錯 8 Object o = list.get(0); 9 System.out.println(list); 10 11 ArrayList<Integer> list1 = new ArrayList<>(); 12 list1.add(34); 13 // printCollection1(list1);//報錯了,原因因為這裡要接收的是List<Object>,那麼可以接收的有ArrayList<Object>或者List<Object>等與List<Object>有繼承關係的集合,但是無法接收ArrayList<Integer>,因為和List<Object>沒有繼承關係,寫成List<?>才能使用 14 printCollection(list1);//?萬用字元可以正常接收 15 } 16 17 public static void printCollection (List<?> col){//此方法使用了無限萬用字元 18 for (Object object : col) { 19 System.out.println(object); 20 } 21 } 22 public static void printCollection1 (List<Object> col){//此方法沒有使用泛型萬用字元 23 for (Object object : col) { 24 System.out.println(object); 25 } 26 } 27 28 }

      2.上界萬用字元<? extends E>的使用:可以傳入E和E的子類

A <? extends E>作為形參時例如List<? extends E>可以使用集合的get方法來獲取E或者E型別本身的元素。

原因分析:當我們用get方法時我們其實是在獲取集合裡內部的元素,但是我們的集合的資料型別還沒有確定,但是我們可以獲得一些明確的已知條件,那就是在<? extends E>中最大的型別是E,而且這個E最大是Object,所以我們可以利用這一點,那麼我們就可以清楚地瞭解到該集合裡面的獲取的元素肯定是E或者Object的子類,他們的範圍肯定小於E或者Object,那麼我們就可以用Object和E這兩個範圍比集合裡面的元素大的類去接收集合裡面的元素。(注:可能略顯囉嗦但是我就是想解釋清楚。)


B 在使用上界萬用字元時,無法呼叫add方法來新增非null的元素。

原因分析:由於上面已經說得很清楚了,<? extends E>作為形參時例如List<? extends E>這時最大型別是E和Object,但是我們不清楚最小的型別是什麼,因為此時?這個萬用字元沒有被賦值,我們呼叫add方法是要新增集合元素或者集合元素的子類,但是我們沒法明確肯定該集合元素型別,或者比該集合元素範圍更小的子類,那麼Java就不會允許新增元素。

 1 public class WildCardTest2 {
 2 
 3     public static void main(String[] args) {
 4         ArrayList<? extends Number> list = new ArrayList<>();
 5 //        list.add(3);報錯了,無法新增非null元素
 6         list.add(null);//沒有報錯
 7         Object o = list.get(0);//用Object接收沒有報錯
 8         Number n = list.get(0);//用Number接收沒有報錯
 9     }
10 
11 }

       3.下界萬用字元<? super E>的使用:可以傳入E或者E的父類

A 在使用下界萬用字元時,無法使用get方法獲取Object以外的元素,或者需要向下轉型,但是可能出現ClassCastException的異常。

原因分析:上界萬用字元,在使用get方法的時候,此時型別沒有明確還是問號?我們只能明確其最大父類或者介面時,我們才能接收,但是我們只能明白<? super E>作為形參時例如List<? super E>時,只能明確Object是最大父類,其他的一概不知,所以只能Object o = list.get(0)。


B 可以使用集合的add方法新增E或者E的子類。

原因分析:上界萬用字元已經解釋很清楚了,add方法新增元素時,?型別不確定就要明確該?型別的最小子類,只要比可能存在的最小子類或者子介面小的任意引用資料型別的物件,我們都可以將其新增,而下界萬用字元<? super E>當作形參時例如List<? super E>,此時E就是最小子類,此時add方法可以新增E或者E的父類或者介面。

 1 public class WildCardTest3 {
 2 
 3     public static void main(String[] args) {
 4         ArrayList<? super Number> list = new ArrayList<>();
 5         list.add(3);//沒有報錯,自動裝箱成Integer,Number的子類
 6         list.add(3.4F);//沒有報錯,自動裝箱成Float,Number的子類
 7         list.add(32L);//沒有報錯,自動裝箱成Long,Number的子類
 8         Object o = list.get(1);
 9 //        Integer i = list.get(0);//報錯了,無法用Integer接收
10     }
11 
12 }

<二>對PECS原則的解讀

      1.什麼是PECS原則?

            PECS是Producer Extends Consumer Super的遞迴縮寫,是Java中使用泛型萬用字元的原則。

    2.阿里巴巴的萬用字元使用規約

泛型萬用字元<? extends T>來接收返回的資料,此寫法的泛型集合不能使用 add 方法,而 < ? super T> 不能使用 get 方法,做為介面呼叫賦值時易出錯。
說明:擴充套件說一下 PECS<Producer Extends Consumer Super> 原則:第一、頻繁往外讀取內容的,適合用<? extends E>。第二、經常往裡插入的,適合用<? super E> 。

      3.對PECS原則的簡單解讀

字面意思是生產者要被繼承要被當作上界萬用字元<? extends E>的上界E,消費者要繼承其他類要被當成下界萬用字元<? super E>的下界E,再借助下阿里巴巴的泛型開發規約去理解下,應該就是當這個被傳入的型別需要進行很多get操作獲取資料的話,那麼請使用上界萬用字元這時這個上界就如同生產者一樣,因為它能被不斷get到,而當需要不斷進行add方法新增資料的話,請使用下界萬用字元這時這個下界就如同消費者一樣,因為它不斷地索取,因為我們在不斷地add元素給它。

相關推薦

Java字元個人理解集合

二、泛型萬用字元講解  <一>萬用字元的使用以及程式碼演示       1.無限萬用字元<?>的使用:可以傳入任何引用資料型別 A 在呼叫方法時使用?萬用字元的過程中無法使用add方法。原因分析:因為萬用字元?代表任意的資料型別,但是當我們呼叫的時候或者用在方法的宣告上,其實這個

Java下載檔案TIM

package download; import java.io.InputStream; import java.io.RandomAccessFile; import java.net.HttpURLConnection; import java.net.URL;

yolo訓練自己的資料集車牌

我看了網上很多yolo教程,可能是因為電腦環境和配置的不一樣,所以我並沒有完全通過網上教程成功訓練自己的資料集,接下來我將我自己完全親自測試並且最後成功訓練資料集的教程記錄如下: 訓練自己的資料集有如

技術乾貨丨Java Web本地提權以及資料劫持思路Tomcat

最近偶然接觸到一個Java的不常用的特性:instrument。簡單來說,這個特性允許你在程式執行之前改變任意類檔案的位元組碼。 簡單的instrument例子大家可以百度,相當多。 而在執行Java程式的時候,只需要加上一個選項即可執行寫好的instrument jar包,如:java -javaa

Java技術_基礎技術0002_中介軟體啟動class載入順序tomcat

基礎技術: Tomcat的class載入的優先順序一覽 1.$JAVA_HOME/jre/lib/ext/下的jar檔案。 2.環境變數CLASSPATH中的jar和class檔案。

java 傳送郵件和讀取郵件163郵箱

1,傳送郵件 (1)在設定裡面開啟163郵箱的smtp、pop3,設定授權碼 (2)在引用pom.xml中引用mail.jar <dependency > <groupId >com.sun.mail </groupId &g

通過JDBC進行簡單的增刪改查MySQL

mage ron end main exce javax xtend 探索 rman 通過JDBC進行簡單的增刪改查(以MySQL為例) 目錄 前言:什麽是JDBC 一、準備工作(一):MySQL安裝配置和基礎學習 二、準備工作(二):下載數據庫對應的jar包並

自定義shell終端提示符及顏色 Centos

工作目錄 con bashrc func global 目錄 藍色 顯示 inux Linux修改Shell命令提示符及顏色 1. Linux登錄過程中加載配置文件順序: /etc/profile → /etc/profile.d/*.sh → ~/.bash_pro

11代碼重用思想遊戲

class 我想 就是 cas == 點擊 ~~ 重用 body 1)情況說明:      假如 我想在我的遊戲上 顯示以惡搞菜單 然後這個菜單 顯示1和2           要是我用鼠標點擊1 ,就可以玩 貪吃蛇遊戲           要是我用鼠標點擊

通過JDBC進行簡單的增刪改查MySQL轉載

IE trac archive solver ttl 賦值 TP 定義 for 轉載:https://www.cnblogs.com/wuyuegb2312/p/3872607.html 目錄 前言:什麽是JDBC 一、準備工作(一):MySQL安裝配置和基礎學習 二、準備

阿裏雲修改主機名centOS

主機 str name 按鍵 ID In 保存 ray ike 需要更改配置文件生效,修/etc/sysconfig/network裏的 HOSTNAME=主機名(可自定義),重啟生效。 如何修改? 1.[root@aliyunbaike ~]# cd /etc/sysco

OpenGL學習 著色器渲染Android

back lse setw %d 編譯 clas ddr attr type 一、Android平臺上下文環境的創建及初始化 1. 首先實例化Android上下文環境,即EGL的初始化。 bool EGLCore::init(EGLContext sharedContex

linux正則表達式,grep

ant per egrep 大小寫 則表達式 spa 表示 中括號 第四章 第一章 基礎正則表達式^word 匹配以word開頭的內容word$ 匹配以我word結尾的內容^$ 表示空行. 代表有且只代表任意一個字符\ 轉義符號,例如. 就只代表點本身,讓有著特殊身份意義

webpack 構建多頁面應用regularjs

webpack-regular github原始碼: https://github.com/fisher-zh/webpack-regular 基於webpack構建的多頁面網站開發環境。 webpack在前端開發的過程中逐漸扮演著越來越重要的角色,在使用vue

WLC-WLC升級2504

1、WLC升級需要按照升級路徑來操作,低版本到高版本的跨度太大,往往需要升級到中間版本,有時候還涉及到FUS。 2、我們升級,一般使用的筆記本上執行的TFTP/FTP  server。 需要注意:筆記本防火牆的影響。 如下是一個升級的簡單示例: 注意,筆記本防火牆因素。(Cisc

天地圖專題七:行政區域標記,熱力圖廣西

天地圖方面的文章已很久不寫。 主要是因為上一個專案結束,基本就不用天地圖了。用百度地圖的可能更大一些。   最近上個專案甲方想搞一個類似熱力圖,熱點圖的東西。在天地圖API上沒有找到類似的直接畫熱力圖的介面,只好用了一些替代的方法。 天地圖行政區域,行政區劃直接介面也沒找到,用

遞迴與迭代的聯絡以及優缺點c++

 1.遞迴的定義: 程式直接或間接的呼叫自身的方法。 遞迴演算法的特點:(1) 遞迴就是在過程或函式裡呼叫自身。(2) 在使用遞迴策略時,必須有一個明確的遞迴結束條件,稱為遞迴出口。(3) 遞迴演算法解題通常顯得很簡潔,但遞迴演算法解題的執行效率較低。所以一般不提倡用遞迴演算法設計程式。(4) 在遞迴呼叫

CMakeList.txt在大型檔案應用前端

基本的CMakeLists.txt並不難,主要有生成庫、生成執行檔案、連結二者以及找庫、找標頭檔案、生成執行檔案、連結庫和執行檔案兩種方法組成。 但是遇到大型庫的編寫,目標是生成一個新的大型庫myslam,生成執行檔案、連結二者。需要提前宣告生成執行檔案在bin,庫在lib中,並把OPenCV、

jenkins介紹及安裝步驟centos7

dha 連接 -i rman 發布 zone 安裝步驟 ges 分享圖片 一、 介紹Jenkins是一個開源軟件項目,是基於Java開發的一種持續集成工具,用於監控持續重復的工作,旨在提供一個開放易用的軟件平臺,使軟件的持續集成變成可能二、 作用1、持續的軟件版本發布/

Map集合遍歷的方式HashMap

color reac pri 循環 next code 方式 new 利用 環境:jdk1.8 HashMap的遍歷方式有多種,下面將會一一列出。 首先我們先在HashMap中添加幾個鍵值對。 HashMap<Integer, String> map = ne