国产 无码 综合区,色欲AV无码国产永久播放,无码天堂亚洲国产AV,国产日韩欧美女同一区二区

Java 泛型中的通配符詳解

這篇具有很好參考價值的文章主要介紹了Java 泛型中的通配符詳解。希望對大家有所幫助。如果存在錯誤或未考慮完全的地方,請大家不吝賜教,您也可以點擊"舉報違法"按鈕提交疑問。

目錄

1、如何定義和使用上界通配符?

2、如何定義和使用無界通配符?

3、如何定義和使用下界通配符?

4、如何使用通配符定義泛型類或接口之間的子類型關系?

5、通配符的捕獲和輔助方法

6、通配符使用指南


????????在泛型代碼中,問號(?)稱為通配符,用來表示未知類型。通配符可以在多種情況下使用:如作為參數(shù)、字段或局部變量的類型;有時也可以作為返回類型。另外,通配符永遠不會用作調用泛型方法、創(chuàng)建泛型類或超類型實例的類型參數(shù)。

????????為什么使用通配符?

????????在 Java 中,類和數(shù)組之間的對象關系是可以繼承的,比如 Dog?extends Animal,那么 Animal[] 與 Dog[] 就是兼容的。但是集合之間卻不存在這種關系,也就是說 List<Animal> 不是List<Dog> 的父類,他們之間沒有任何關系。那么為了建立兩個集合之間的聯(lián)系,就需要用到通配符。// 只是其中一部分原因

1、如何定義和使用上界通配符?

????????可以使用上界通配符來放寬對變量的限制。例如,你想編寫一個方法,該方法適用于List<Integer>, List<Double> 和 List<Number>;就可以通過使用上界通配符來實現(xiàn)這一點。

????????聲明一個上界通配符,需要使用通配符 ('?'),跟上 extends 關鍵字,然后再跟它的上界。比如,編寫用于 Number 列表和 Number 子類型(如 Integer、Double 和 Float)的方法,可以指定 List<? extends Number>。List<? extends Number> 要比 List<Number> 對類型的限制更加寬松,因為 List<Number> 只匹配類型為 Number 的列表,而 List<? extends Number> 匹配類型為 Number 或其任何子類的列表。

????????例如下邊的程序代碼:

public static void process(List<? extends Foo> list) { /* ... */ }

????????上界通配符 <? extends Foo> 中的 Foo 匹配 Foo 類型和 Foo 的任何子類型。process() 方法可以訪問類型為?Foo 的列表元素:

public static void process(List<? extends Foo> list) {
    for (Foo elem : list) {
        // ...
    }
}

????????在 foreach 子句中,elem 變量迭代列表中的每個元素。在 elem 元素上可以使用 Foo 類中定義的任何方法

? ? ? ? 如下,sumOfList()?方法返回列表中數(shù)字的和:

public static double sumOfList(List<? extends Number> list) {
    double s = 0.0;
    for (Number n : list)
        s += n.doubleValue();
    return s;
}

????????下面的代碼,使用一個 Integer 對象列表,輸出 sum = 6.0:

List<Integer> li = Arrays.asList(1, 2, 3);
System.out.println("sum = " + sumOfList(li));

????????Double 值列表可以使用相同的 sumOfList() 方法。下面的代碼輸出 sum = 7.0:

List<Double> ld = Arrays.asList(1.2, 2.3, 3.5);
System.out.println("sum = " + sumOfList(ld));

2、如何定義和使用無界通配符?

????????無界通配符類型使用通配符(?)指定,例如 List<?>。在下邊兩種情況下,無界通配符是一種有用的方法:

  1. 編寫一個方法,該方法可以使用 Object 類中提供的功能函數(shù)。
  2. 代碼在泛型類中使用不依賴于類型參數(shù)的方法。例如,List.size 或 List.clear。事實上,Class<?> 之所以如此常用,是因為 Class<T> 中的大多數(shù)方法都不依賴于 T。

????????例如以下 printList()?方法:

public static void printList(List<Object> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}

????????printList() 的目標是用來打印任何類型的列表,但上述代碼中它只能打印 Object 實例的列表;并不能打印?List<Integer>, List<String>, List<Double> 等,因為這些列表不是 List<Object> 的子類型。所以如果要編寫一個通用的 printList() 方法,需要使用到 List<?>:

public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

????????對于任何具體的類型 A,List<A> 都是 List<?> 的子類,可以使用 printList() 打印任何類型的列表:// 解決了之前?List<A> 和?List<B> 無任何關系的問題

List<Integer> li = Arrays.asList(1, 2, 3);
List<String>  ls = Arrays.asList("one", "two", "three");
printList(li);
printList(ls);

????????注意:List<Object> 和 List<?> 是不一樣的??梢詫?Object 或 Object 的任何子類型插入到 List<Object> 中,但是只能將 null 插入到?List<?> 中。

3、如何定義和使用下界通配符?

????????上界通配符將未知類型限制為特定類型的子類型,使用 extends 關鍵字表示。類似地,下界通配符將未知類型限制為特定類型的超類型,使用?super 關鍵字表示。

????????下界通配符使用通配符('?')表示,后面跟著 super 關鍵字,然后再跟著它的下界:<? super A>。

????????注意:可以為通配符指定上界,也可以指定下界,但不能同時都指定。

????????例如,編寫一個將 Integer 對象放入列表的方法。為了最大限度地提高靈活性,該方法需要適用于 List<Integer>、List<Number> 和 List<Object> 等任何可以保存 Integer 值的對象。那么要編寫處理 Integer 列表和 Integer 超類型列表的方法,就可以使用 List<? super Integer> 來指定。如以下代碼將數(shù)字 1 到 10 添加到列表的末尾:

public static void addNumbers(List<? super Integer> list) {
    for (int i = 1; i <= 10; i++) {
        list.add(i);
    }
}

4、如何使用通配符定義泛型類或接口之間的子類型關系?

????????泛型類或接口之間的關聯(lián)并不取決于它們的類型之間是否存在關聯(lián)。不過,我們可以使用通配符來創(chuàng)建泛型類或接口之間的關聯(lián)關系。

????????給定以下兩個非泛型類:

class A { /* ... */ }
class B extends A { /* ... */ }

????????編寫以下代碼是合理的:

B b = new B();
A a = b;

????????上邊這個例子表明常規(guī)類的繼承遵循子類型的規(guī)則:如果 B 繼承 A,那么 B.calss 就是 A.calss?的子類型。但是這個規(guī)則并不適用于泛型類型:

List<B> lb = new ArrayList<>();
List<A> la = lb;   // compile-time error

????????假設 Integer 是 Number 的子類型,那么 List<Integer> 和 List<Number> 之間的關系是什么呢?

Java 泛型中的通配符詳解

????????雖然 Integer 是 Number 的子類型,但 List<Integer> 并不是 List<Number> 的子類型,所以,這兩種類型并不相關。事實上,List<Number> 和 List<Integer> 的公共父類是 List<?>。

????????為了在這些類之間創(chuàng)建關系,讓代碼可以通過 List<Integer> 的元素訪問 Number 的方法,可以使用一個上界通配符:

List<? extends Integer> intList = new ArrayList<>();
List<? extends Number>  numList = intList;  // OK. List<? extends Integer> is a subtype of List<? extends Number>

????????因為 Integer 是 Number 的子類型,而 numList 是 Number 對象的列表,所以 intList (Integer對象的列表)和 numList 之間存在關聯(lián)關系。下圖顯示了用上下界通配符聲明的幾個 List 類之間的關系。// 使用通配符可以定義兩個類型之間的關系

Java 泛型中的通配符詳解

5、通配符的捕獲和輔助方法

????????在某些情況下,編譯器會自動推斷通配符的類型。例如,列表可以定義為 List<?>,但是,當計算表達式時,編譯器會從代碼中推斷出特定的類型,這種場景稱為通配符捕獲。

????????大多數(shù)情況下,都不需要擔心通配符的捕獲,除非看到包含短語 “capture of” 的錯誤消息。

????????如下,WildcardError 示例會在編譯時會產生一個捕獲錯誤:

import java.util.List;

public class WildcardError {

    void foo(List<?> i) {
        i.set(0, i.get(0));
    }
}

????????在本例中,編譯器將 i 輸入形參處理為 Object 類型。當 foo 方法調用 List.set(int, E) 時,編譯器無法確認插入到列表中的對象類型,所以會產生錯誤。當發(fā)生這種類型的錯誤時,通常意味著編譯器認為給變量分配了錯誤的類型。將泛型添加到 Java 語言中就是出于這個原因——在編譯時加強類型安全。

????????當使用 Oracle 的 JDK 7 javac 實現(xiàn)編譯時,WildcardError 示例會生成以下錯誤:

WildcardError.java:6: error: method set in interface List<E> cannot be applied to given types;
    i.set(0, i.get(0));
     ^
  required: int,CAP#1
  found: int,Object
  reason: actual argument Object cannot be converted to CAP#1 by method invocation conversion
  where E is a type-variable:
    E extends Object declared in interface List
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?
1 error

????????在本例中,代碼試圖執(zhí)行安全操作,那么如何解決編譯器錯誤呢?可以通過編寫一個捕獲通配符的私有 helper 方法來修復它。如 WildcardFixed 所示,通過創(chuàng)建私有輔助方法 fooHelper 來解決這個問題:

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }

    // 創(chuàng)建輔助方法,以便可以通過類型推斷捕獲通配符
    private <T> void fooHelper(List<T> l) {
        l.set(0, l.get(0));
    }
}

????????由于使用了 helper 方法,編譯器使用推斷來確定調用中的 T 是 CAP#1,即捕獲變量。示例現(xiàn)在編譯成功。

6、通配符使用指南

????????在使用泛型進行編程時,讓人比較困惑的是需要確定何時使用上界通配符,何時使用下界通配符。本節(jié)提供了一些設計代碼時要遵循的指導原則。// 以下是來自官方的指導原則

????????為了方便理解,可以將變量看作以下兩種形式:

  • “in” 變量:“in” 變量為代碼提供數(shù)據(jù)。比如一個復制方法有兩個參數(shù):copy(src, dest)。src 參數(shù)提供了需要復制的數(shù)據(jù),因此它是 “in” 形參。
  • “out” 變量:“out” 變量用來保存輸出數(shù)據(jù),便于該數(shù)據(jù)在其他地方使用。在 copy(src, dest) 方法中, dest 參數(shù)用來接收數(shù)據(jù),因此它是 "out" 形參。

????????當然,有些變量同時用于 “輸入” 和 “輸出” 目的,下邊指南中也提到了這種情況。

????????在決定是否使用通配符以及使用什么類型的通配符時,可以使用 “in” 和 “out” 原則。以下列表提供了需要遵循的指導方針:

  1. 對于 “in” 變量,可以定義一個上界通配符,使用 extends 關鍵字。
  2. 對于“out”變量,可以定義一個下界通配符,使用 super 關鍵字。
  3. 如果 “in” 變量可以使用 Object.calss 中定義的方法對其進行訪問,可以使用無界通配符。
  4. 如果變量同時用于 “輸入” 和 “輸出”的情況下,不要使用通配符。// 限定唯一的類型

? ? ? ? 以上這些準則不適用于方法的返回類型。應該避免使用通配符作為方法的返回類型,因為它會迫使使用代碼的程序員去處理通配符。

????????List<? extends ...> 可以認為它是只讀的,但并不能進行嚴格的保證,假設有以下兩個類:

class NaturalNumber {

    private int i;

    public NaturalNumber(int i) { this.i = i; }
    // ...
}

class EvenNumber extends NaturalNumber {

    public EvenNumber(int i) { super(i); }
    // ...
}

????????考慮下面的代碼:

List<EvenNumber> le = new ArrayList<>();
List<? extends NaturalNumber> ln = le;
ln.add(new NaturalNumber(35));  // 編譯錯誤

????????因為 List<EvenNumber> 是 List<? extends NaturalNumber> 的子類型,所以可以將 le 賦值給 ln。但是卻不能用 ln 把一個自然數(shù)加到一個偶數(shù)列表中。在該列表中只可以進行以下操作:

  1. 添加 null 元素。
  2. 調用 clear() 方法。
  3. 獲取迭代器并調用 remove() 方法。
  4. 捕獲通配符并寫入從列表中讀取的元素。

????????所以,從嚴格意義上來講,List<? extends NaturalNumber> 并不是只讀的,但是卻可以認為它是只讀的,因為不能在列表中存儲新的元素或更改現(xiàn)有元素文章來源地址http://www.zghlxwxcb.cn/news/detail-495326.html

到了這里,關于Java 泛型中的通配符詳解的文章就介紹完了。如果您還想了解更多內容,請在右上角搜索TOY模板網(wǎng)以前的文章或繼續(xù)瀏覽下面的相關文章,希望大家以后多多支持TOY模板網(wǎng)!

本文來自互聯(lián)網(wǎng)用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。如若轉載,請注明出處: 如若內容造成侵權/違法違規(guī)/事實不符,請點擊違法舉報進行投訴反饋,一經查實,立即刪除!

領支付寶紅包贊助服務器費用

相關文章

  • 了解java中的通配符“?“

    了解java中的通配符“?“

    目錄 通配符的作用 ????????先看一段代碼 ????????用通配符\\\"?\\\"后,代碼變化 ????????結論 通配符上界? 通配符下界 對通配符上下界的注釋理解及其練習代碼?? 簡記: ? ?用于在泛型的使用,即為通配符. 在Java中,通配符(wildcard)主要用于泛型編程,用于表示一個

    2024年02月10日
    瀏覽(25)
  • Linux詳解:通配符

    Linux詳解:通配符

    Linux是一款開源操作系統(tǒng),其靈活性和可定制性一直受到開發(fā)者的喜愛和追捧。而且,Linux在文件管理方面提供了豐富的功能,例如通配符,它是一種用于匹配文件名的特殊字符。通配符在Linux中可以幫助我們更加方便和快捷地查找和操作文件。本文將介紹Linux中常用的通配符

    2024年02月09日
    瀏覽(56)
  • office辦公技能|word中的常見通配符使用

    office辦公技能|word中的常見通配符使用

    操作方法: 1、快捷鍵 Ctrl+H,打開Word的查找替換窗口,單擊【更多】按鈕,勾選“使用通配符”。 2、在查找內容處,輸入“替換內容*^13”,替換為處什么都不填。 3、單擊【全部替換】。 (1)點擊【開始】-【編輯】-【替換】按鈕或按【Ctrl+H】組合鍵,打開“查找與替換”

    2024年01月20日
    瀏覽(26)
  • SHELL 基礎 入門(三) Bash 快捷鍵 命令執(zhí)行順序,詳解通配符

    SHELL 基礎 入門(三) Bash 快捷鍵 命令執(zhí)行順序,詳解通配符

    目錄 Bash 常用快捷鍵? 輸入輸出重定向? 用法? 輸出重定向? 命令執(zhí)行順序? ;? 分號 ||? 通配符? 傳統(tǒng)通配符? ? \\\'? *? \\\'? [? ]?? [ - ]?? [ ^ ] 常用字符? 強調 : {? }? ?生成序列? Ctrl + A? ? 把光標移動到命令行開頭 Ctrl + E? ? 把光標移動到命令行尾? Ctrl + D? ? 退出當前

    2024年02月11日
    瀏覽(44)
  • 數(shù)據(jù)結構(Java實現(xiàn))-字符串常量池與通配符

    數(shù)據(jù)結構(Java實現(xiàn))-字符串常量池與通配符

    字符串常量池 在Java程序中,類似于:1, 2, 3,3.14,“hello”等字面類型的常量經常頻繁使用,為了使程序的運行速度更快、更節(jié)省內存,Java為8種基本數(shù)據(jù)類型和String類都提供了常量池。 “池” 是編程中的一種常見的, 重要的提升效率的方式, 我們會在未來的學習中遇到各

    2024年02月10日
    瀏覽(24)
  • Elasticsearch 通配符查詢

    通配符查詢(wildcard query) 匹配字段被通配符表達式(沒有被分析)匹配的文檔。支持的通配符為*(匹配任意字符序列,包括空字符序列)以及?(匹配任意單字符)。注意,此查詢可能會很慢,它需要迭代許多字段值。為了防止極慢的通配符匹配,通配符字段值不能以一個

    2024年02月11日
    瀏覽(28)
  • 活用 命令行通配符

    活用 命令行通配符

    本文是對 阮一峰老師 命令行通配符教程 [1] 的學習與記錄 通配符早于正則表達式出現(xiàn),可以看作是原始的正則表達式. 其功能沒有正則那么強大靈活,而勝在簡單和方便. - 字符 切回上一個路徑/分支 如圖: !! 代表上一個命令, 如圖: [Linux中“!\\\"的神奇用法](https://www.cnblogs.com/bian

    2024年02月10日
    瀏覽(25)
  • 【類型通配符】

    為了表示各種泛型List的父類,可以使用類型通配符 類型通配符:? List?:表示元素類型未知的List,它的元素可以匹配任何的類型 這種帶通配符的List僅表示它是各種泛型List的父類,并不能把元素添加到其中 如果不想讓List?是任何泛型的父類,只想讓它代表某一類泛型List的父

    2024年02月17日
    瀏覽(58)

覺得文章有用就打賞一下文章作者

支付寶掃一掃打賞

博客贊助

微信掃一掃打賞

請作者喝杯咖啡吧~博客贊助

支付寶掃一掃領取紅包,優(yōu)惠每天領

二維碼1

領取紅包

二維碼2

領紅包