欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

Java中 ? extends T 和 ? super T的理解

 更新時(shí)間:2022年05月17日 11:23:40   作者:一葉飄舟  
本文主要介紹了Java中 ? extends T 和 ? super T的理解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧

? 通配符類型

  • <? extends T> 表示類型的上界,表示參數(shù)化類型的可能是T 或是 T的子類;
  • <? super T> 表示類型下界(Java Core中叫超類型限定),表示參數(shù)化類型是此類型的超類型(父類型),直至Object;

上界<? extends T>不能往里存,只能往外取

比如,我們現(xiàn)在定義:List<? extends T>首先你很容易誤解它為繼承于T的所有類的集合,你可能認(rèn)為,你定義的這個(gè)List可以用來(lái)put任何T的子類,那么我們看下面的代碼:

import java.util.LinkedList;
import java.util.List;

public class test {
? ? public static void main(String[] args) {
? ? ? ? List<? extends Father> list = new LinkedList<>();
? ? ? ? list.add(new Son());
? ? }
}
class Human{
}
class Father extends Human{
}
class Son extends Father{
}
class LeiFeng extends Father {
}

list.add(new Son());這行會(huì)報(bào)錯(cuò):The method put(Son) is undefined for the type List<capture#1-of ? extends Father>

List<? extends Father> 表示 “具有任何從Son繼承類型的列表”,編譯器無(wú)法確定List所持有的類型,所以無(wú)法安全的向其中添加對(duì)象。可以添加null,因?yàn)閚ull 可以表示任何類型。所以List 的add 方法不能添加任何有意義的元素,但是可以接受現(xiàn)有的子類型List 賦值。

你也許試圖這樣做:

List<? extends Father> list = new LinkedList<Son>();
list.add(new Son());

即使你指明了為Son類型,也不能用add方法添加一個(gè)Son對(duì)象。

list中為什么不能加入Father類和Father類的子類呢,我們來(lái)分析下。

List<? extends Father>表示上限是Father,下面這樣的賦值都是合法的

   List<? extends Father> list1 = new ArrayList<Father>();
   List<? extends Father> list2 = new ArrayList<Son>();
   List<? extends Father> list3 = new ArrayList<LeiFeng>();

如果List<? extends Father>支持add方法的話:

  • list1可以add Father和所有Father的子類;
  • list2可以add Son和所有Son的子類;
  • list3可以add LeiFeng和所有LeiFeng的子類。

下面代碼是編譯不通過(guò)的:

list1.add(new Father());//error
list1.add(new Son());//error

原因是編譯器只知道容器內(nèi)是Father或者它的派生類,但具體是什么類型不知道。可能是Father?可能是Son?也可能是LeiFeng,XiaoMing?編譯器在看到后面用Father賦值以后,集合里并沒(méi)有限定參數(shù)類型是“Father“。而是標(biāo)上一個(gè)占位符:CAP#1,來(lái)表示捕獲一個(gè)Father或Father的子類,具體是什么類不知道,代號(hào)CAP#1。然后無(wú)論是想往里插入Son或者LeiFeng或者Father編譯器都不知道能不能和這個(gè)CAP#1匹配,所以就都不允許。

所以通配符<?>和類型參數(shù)的區(qū)別就在于,對(duì)編譯器來(lái)說(shuō)所有的T都代表同一種類型。比如下面這個(gè)泛型方法里,三個(gè)T都指代同一個(gè)類型,要么都是String,要么都是Integer。

public <T> List<T> fill(T... t);

但通配符<?>沒(méi)有這種約束,List<?>單純的就表示:集合里放了一個(gè)東西,是什么我不知道。

所以這里的錯(cuò)誤就在這里,List<? extends Father>里什么都放不進(jìn)去。

List<? extends Father> list不能進(jìn)行add,但是,這種形式還是很有用的,雖然不能使用add方法,但是可以在初始化的時(shí)候一個(gè)Season指定不同的類型。比如:

List<? extends Father> list1 = getFatherList();//getFatherList方法會(huì)返回一個(gè)Father的子類的list

另外,由于我們已經(jīng)保證了List中保存的是Father類或者他的某一個(gè)子類,所以,可以用get方法直接獲得值:

List<? extends Father> list1 = new ArrayList<>();
Father father = list1.get(0);//讀取出來(lái)的東西只能存放在Father或它的基類里。
Object object = list1.get(0);//讀取出來(lái)的東西只能存放在Father或它的基類里。
Human human = list1.get(0);//讀取出來(lái)的東西只能存放在Father或它的基類里。
Son son = (Son)list1.get(0);

下界<? super T>不影響往里存,但往外取只能放在Object對(duì)象里

下界用super進(jìn)行聲明,表示參數(shù)化的類型可能是所指定的類型,或者是此類型的父類型,直至Object。

//super只能添加Father和Father的子類,不能添加Father的父類,讀取出來(lái)的東西只能存放在Object類里
List<? super Father> list = new ArrayList<>();
list.add(new Father());
list.add(new Human());//compile error 
list.add(new Son());
Father person1 = list.get(0);//compile error 
Son son = list.get(0);//compile error 
Object object1 = list.get(0);

因?yàn)橄陆缫?guī)定了元素的最小粒度的下限,實(shí)際上是放松了容器元素的類型控制。既然元素是Father的基類,那往里存粒度比Father小的都可以。出于對(duì)類型安全的考慮,我們可以加入Father對(duì)象或者其任何子類(如Son)對(duì)象,但由于編譯器并不知道List的內(nèi)容究竟是Father的哪個(gè)超類,因此不允許加入特定的任何超類(如Human)。而當(dāng)我們讀取的時(shí)候,編譯器在不知道是什么類型的情況下只能返回Object對(duì)象,因?yàn)镺bject是任何Java類的最終祖先類。但這樣的話,元素的類型信息就全部丟失了。

PECS原則

最后看一下什么是PECS(Producer Extends Consumer Super)原則,已經(jīng)很好理解了:

  • 頻繁往外讀取內(nèi)容的,適合用上界Extends。
  • 經(jīng)常往里插入的,適合用下界Super。

總結(jié)

  • extends 可用于返回類型限定,不能用于參數(shù)類型限定(換句話說(shuō):? extends xxx 只能用于方法返回類型限定,jdk能夠確定此類的最小繼承邊界為xxx,只要是這個(gè)類的父類都能接收,但是傳入?yún)?shù)無(wú)法確定具體類型,只能接受null的傳入)。
  • super 可用于參數(shù)類型限定,不能用于返回類型限定(換句話說(shuō):? supper xxx 只能用于方法傳參,因?yàn)閖dk能夠確定傳入為xxx的子類,返回只能用Object類接收)。
  • ? 既不能用于方法參數(shù)傳入,也不能用于方法返回。

帶有super超類型限定的通配符可以向泛型對(duì)象中寫入,帶有extends子類型限定的通配符可以向泛型對(duì)象讀取。

到此這篇關(guān)于Java中 ? extends T 和 ? super T的理解的文章就介紹到這了,更多相關(guān)Java中 ? extends T 和 ? super T內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

  • MyBatisPlus之id生成策略的方法

    MyBatisPlus之id生成策略的方法

    本文主要介紹了MyBatisPlus之id生成策略的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2023-03-03
  • myatisplus的saveOrUpdate的提交總是update問(wèn)題

    myatisplus的saveOrUpdate的提交總是update問(wèn)題

    這篇文章主要介紹了myatisplus的saveOrUpdate的提交總是update問(wèn)題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-11-11
  • 超好用的Java工具類庫(kù)Hutool用法詳解

    超好用的Java工具類庫(kù)Hutool用法詳解

    Hutool是一個(gè)小而全的Java工具類庫(kù),通過(guò)靜態(tài)方法封裝,降低相關(guān)API的學(xué)習(xí)成本,提高工作效率,下面就跟隨小編一起來(lái)學(xué)習(xí)一下Hutool的具體用法吧
    2023-09-09
  • Java數(shù)據(jù)結(jié)構(gòu)之常見(jiàn)排序算法(下)

    Java數(shù)據(jù)結(jié)構(gòu)之常見(jiàn)排序算法(下)

    這篇文章主要介紹了Java數(shù)據(jù)結(jié)構(gòu)之常見(jiàn)排序算法(下),與之相對(duì)有(上),想了解的朋友可以去本網(wǎng)站掃搜,在這兩篇文章里涵蓋關(guān)于八大排序算法的所有內(nèi)容,需要的朋友可以參考下
    2023-01-01
  • SpringBoot日志進(jìn)階實(shí)戰(zhàn)之Logback配置經(jīng)驗(yàn)和方法

    SpringBoot日志進(jìn)階實(shí)戰(zhàn)之Logback配置經(jīng)驗(yàn)和方法

    本文給大家介紹在SpringBoot中使用Logback配置日志的經(jīng)驗(yàn)和方法,并提供了詳細(xì)的代碼示例和解釋,包括:滾動(dòng)文件、異步日志記錄、動(dòng)態(tài)指定屬性、日志級(jí)別、配置文件等常用功能,覆蓋日常Logback配置開(kāi)發(fā)90%的知識(shí)點(diǎn),感興趣的朋友跟隨小編一起看看吧
    2023-06-06
  • intellij IDEA配置springboot的圖文教程

    intellij IDEA配置springboot的圖文教程

    Spring Boot是由Pivotal團(tuán)隊(duì)提供的全新框架,其設(shè)計(jì)目的是用來(lái)簡(jiǎn)化新Spring應(yīng)用的初始搭建以及開(kāi)發(fā)過(guò)程。接下來(lái)通過(guò)本文給大家介紹intellij IDEA配置springboot的圖文教程,感興趣的朋友一起看看吧
    2018-03-03
  • SpringBoot @Autowired注解注入規(guī)則介紹

    SpringBoot @Autowired注解注入規(guī)則介紹

    這篇文章主要介紹了SpringBoot @Autowired注解注入規(guī)則介紹,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。
    2021-11-11
  • 詳解Spring Boot中Controller用法

    詳解Spring Boot中Controller用法

    Controller是SpringBoot里最基本的組件,他的作用是把用戶提交來(lái)的請(qǐng)求通過(guò)對(duì)URL的匹配,分配個(gè)不同的接收器,再進(jìn)行處理,然后向用戶返回結(jié)果。下面通過(guò)本文給大家介紹Spring Boot中Controller用法,需要的朋友參考下
    2017-05-05
  • java 重載(overload)與重寫(override)詳解及實(shí)例

    java 重載(overload)與重寫(override)詳解及實(shí)例

    這篇文章主要介紹了java 重載(overload)與重寫(override)詳解及實(shí)例的相關(guān)資料,并附實(shí)例代碼,需要的朋友可以參考下
    2016-10-10
  • Java中的代理模式詳解及實(shí)例代碼

    Java中的代理模式詳解及實(shí)例代碼

    這篇文章主要介紹了Java中的代理模式詳解及實(shí)例代碼的相關(guān)資料,這里附有實(shí)例代碼,需要的朋友可以參考下
    2017-02-02

最新評(píng)論