java基礎-泛型2

来源:http://www.cnblogs.com/justforcon/archive/2016/11/19/6073825.html
-Advertisement-
Play Games

6 類型推測 java編譯器能夠檢查所有的方法調用和對應的聲明來決定類型的實參,即類型推測,類型的推測演算法推測滿足所有參數的最具體類型,如下例所示: 6.1 泛型方法的類型推測 類型的推測可以使泛型方法的使用語法和普通的方法一樣,不必指定尖括弧內的類型,如上述例子。 6.2 泛型類的類型推測 對於泛 ...


6 類型推測

  java編譯器能夠檢查所有的方法調用和對應的聲明來決定類型的實參,即類型推測,類型的推測演算法推測滿足所有參數的最具體類型,如下例所示:

//泛型方法的聲明
static <T> T pick(T a1, T a2) { return a2; }
//調用該方法,根據賦值對象的類型,推測泛型方法的類型參數為Serializable
//String和ArrayList<T>都實現介面Serializable,後者是最具體的類型
Serializable s = pick("d", new ArrayList<String>());

6.1 泛型方法的類型推測

  類型的推測可以使泛型方法的使用語法和普通的方法一樣,不必指定尖括弧內的類型,如上述例子。

6.2 泛型類的類型推測

  對於泛型類的使用,java編譯器也可以進行類型的推測,因此調用泛型類時,可以不用指定尖括弧內的類型參數,不過尖括弧不可省略,之前的總結已經提到,空的尖括弧又叫鑽石(中文怪怪的),如下例所示:

//以下用法沒有指定類型參數,尖括弧為空
Map<String, List<String>> myMap = new HashMap<>();
//註意,空的簡括弧不能省略,如下代碼編譯器會發出警告
Map<String, List<String>> myMap = new HashMap();

   上述代碼中的第二個賦值語句中new HashMap() 實際是用的原始類型。

6.3 非泛型類的泛型構造器的類型參數推測

  無論是泛型還是非泛型的類都可以使用泛型的構造器,如方法一樣。

//類定義
class MyClass<X> {
  <T> MyClass(T t) {
    // ...
  }
}
//以下是實例化以上類的表達式
new MyClass<Integer>("")

  以上代碼中的實例化表達式雖然沒有指定構造器的類型參數,但是可以根據傳入的參數推測其類型參數為String。

  java7以前的版本能夠推測出構造其的參數類型,而java7以後,使用鑽石的語法也推測泛型類的參數類型。

  需要註意的是,類型參數的推測演算法只會使用傳入的參數,目的類型或者和明顯的返回類型來推測類型。

6.4 目的類型

  java編譯器充分利用了目的類型來推測泛型方法或者類的類型參數,如下例:

//Collections中的一個方法的聲明如下
static <T> List<T> emptyList();
//現在調用該方法
List<String> listOne = Collections.emptyList();

  以上中的第二個語句中,listOne變數類型為List<string>,就是目的類型,所以需要方法emptyList的返回類型也必須是List<Stirng>,這樣可以推測泛型方法聲明中的T為String,java7和8都可以實現這樣的推測,當然你可以在調用泛型方法時指明方括弧中的類型參數。

  值得註意的是java7中方法的參數還不屬於目的類型,而java8則把方法參數加入目的類型,如下例所示:

//如下方法接受的參數為List<String> 
void processStringList(List<String> stringList) {
    // process stringList
}
//Collections中的emptyList方法的簽名如下
static <T> List<T> emptyList();
//java7中,下列調用語句的編譯會報錯,而java8則不存在這樣的問題
processStringList(Collections.emptyList());

 7 通配符

  在泛型的代碼中問號(?)代表通配符,代表未知的類型,通配符可以用在許多場合,可用作參數,欄位,返回值的類型,但是通配符不能用作方法調用,泛型實例的創建和父類型的實參。

7.1 上限通配符

  利用上限通配符可以放鬆對變數的限制。

  上限通配符的聲明方法如下例所示:

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

  上述聲明的方法,的泛型參數使用了上限通配符,通配符"?"加extends關鍵詞後跟其上限,此處的extends類似於通常意義上的extends和implements,意思是該方法是針對於Number類型的子類型,包括Integer,Float等的列表。

  通配符<? extends Foo>匹配所有的Foo的子類型和Foo類型自身。

7.2 無限制通配符

  無限制通配符就是簡單的"?",如List<?>就代表未知類型的列表,以下兩種情況適合使用無限制通配符:

  • 聲明一個要用到繼承的Object類中的方法時
  • 當代碼中需要用到不依賴於類型參數的泛型類的方法時, 如List.size或者List.clear,Class<?> 經常被用到,因為Class<T>中的許多方法是不依賴於類型參數T的。

以下例子很好的說明使用Object類中的方法時使用無限制通配符的好處:

//普通的方法聲明
public static void printList(List<Object> list) {
    for (Object elem : list)
        System.out.println(elem + " ");
    System.out.println();
}
//使用通配符的泛型作為方法參數,該方法的參數能夠傳入任何類型的列表(List)
public static void printList(List<?> list) {
    for (Object elem: list)
        System.out.print(elem + " ");
    System.out.println();
}

   註意:既然定義了列表List<?>的類型的廣泛性,就要承擔廣泛性的造成的後果,在方法聲明中,只能對List<?>類型的變數插入null,因為你無法預知傳入方法的類型變數,而List<Object>作為參數則可以插入任何類型的對象。

7.3 下限通配符

   與上限通配符類似,下限通配符指定了類型參數的下限,未知的類型必須是指定類型的父類型,下限通配符的寫法:<? super A>,此處關鍵詞為super

  註意:不能同時指定上限和下限。

7.4 通配符和子類型

  之前提到過,泛型之間的關係不僅僅是由他們的類型實參決定的,如不能說List<Number>就是List<Integer>的父類,不過使用通配符可以構成如下關係:

  箭頭表示“是其子類型”的關係,如List<Integer>是List<? extends Integer>的子類型,可以這樣理解:List<Integer>是一種List<? extends Integer>。

7.5 通配符的捕獲與輔助方法

   有時候編譯器會推測通配符的類型,如果一個欄位的類型被定義為List<?>,當運算一個表達式的時候,編譯器會從代碼中推測該欄位為一個特定的類型,這就叫通配符的捕獲。

import java.util.List;
public class WildcardError {
    void foo(List<?> i) {
        i.set(0, i.get(0));
    }
}

 

  上述代碼會編譯出錯,foo方法調用List.set(int,E),編譯器首先將set方法內作為參數的i視為Object類型,無法判斷將要插入的對象類型是否和目標列表類型是否一致,所以編譯不能通過。

  此時可以加入一個輔助方法,使其能能夠順利通過編譯:

public class WildcardFixed {

    void foo(List<?> i) {
        fooHelper(i);
    }
    // 創建輔助方法,調用該方法可以通過類型推測來實現通配符的捕獲
    private <T> void fooHelper(List<T> l) {
        l.set(0, l.get(0));
    }
}

  再來看一下一個例子:

import java.util.List;

public class WildcardErrorBad {

    void swapFirst(List<? extends Number> l1, List<? extends Number> l2) {
      Number temp = l1.get(0);
      l1.set(0, l2.get(0)); 
      l2.set(0, temp);       
    }
}

  上述代碼中的方法功能是將兩個列表的首個元素交換,然而無法判斷兩個傳入的實參的類型參數是否相容,所以,無法編譯通過,此處代碼本質上就是錯誤的,沒有相應的輔助方法。

 7.6 通配符使用原則

  泛型的使用有一點讓人疑惑的就是不知道什麼時候該用上限通配符,什麼時候使用下限通配符,一下是幾點原則:

  為了說明問題,先列出兩種變數1)In變數:作為代碼中的數據來源,比如複製的方法copy(src,dest)中的src參數就是in變數,;2)out變數,在代碼中用來存儲數據作為他用,如copy(src,dest)中的dest參數就是out變數。變數列出之後,說原則:

  • in變數使用上限通配符,使用extends關鍵詞
  • out變數使用下限通配符,使用super關鍵詞
  • 當需要使用的in變數可以通過Object類中的方法訪問時,使用無限制通配符
  • 當代碼中既需要訪問的變數既要當做in變數使用,又要當做out變數使用時,不要使用通配符

  上述原則不試用與方法的返回類型,不建議在返回類型中使用通配符,否則將必須處理通配符的問題。

 


您的分享是我們最大的動力!

-Advertisement-
Play Games
更多相關文章
  • Google-Guice入門介紹(較為清晰的說明瞭流程):http://blog.csdn.net/derekjiang/article/details/7231490 使用Guice,需要添加第三方的包(guice-3.0.jar和javax.inject.jar) 鏈接:http://pan.b ...
  • CSDN最近改規則了,改的越來越不順心,推薦到首頁的文章質量不再受限制,一下子降低了首頁的文章質量。這個消息是在官方博客QQ群裡面看到的,來源很可靠,只是CSDN還沒有發公告而已,又或者也許不必要再發公告了。我覺得這種做法是既損害博客作者的事情,又損害讀者的事情,具體詳情,請參考我的CSDN博文,h ...
  • 一、PHP 標記 當解析一個文件時,PHP 會尋找 起始 和 結束標記 ,也就是``,在標記外的部分會被解析器忽略。 註意 開始標記後面必須跟上一個空白符,否則就會出錯。 二、從 HTML 中分離 凡是在PHP開始和結束標記之外的內容,都會被PHP解析器忽略。例外是使用控制語句時: 三、指令符分隔 ...
  • 測試環境部署結構 測試用例 public @ResponseBody String t1001(Model model,HttpServletRequest request){ PlatformReq req = new PlatformReq().createDemo(); req.setComp ...
  • 抽象類 : 用關鍵字abstract ;一個類如果被abstract修飾那麼這個就叫抽象類。 如果abstract修飾方法 ,那麼這個方法就叫抽象的方法 如果abstract修飾類,那麼這個類叫抽象類。 如果一個類繼承了抽象類,必須要實現抽象類中的抽象方法。 abstract關鍵字的使用: 方法體 ...
  • #!C:\Program Files\Python35/bin# -*- conding:utf-8 -*-# author: Frankuser_input = input("please input your name:") #input 函數的使用print("User input Msg:" ...
  • 軟體工程的構件化道路發展到今天,已經具有成熟的技術。這就像今天的大廈建築一樣,使用預製的構件,就能建造萬丈高樓。同樣道理,使用Spring Boot開發框架,也可以支持這種構件化的功能,正像其官方網站所介紹的那樣,你甚至可以不用寫一行代碼,就可運行一個應用:“Spring Boot makes it ...
  • (一) 下邊使用outputStream位元組輸出流進行寫操作 package zdbIO;import java.io.File;import java.io.FileNotFoundException;import java.io.FileOutputStream;import java.io.I ...
一周排行
    -Advertisement-
    Play Games
  • 移動開發(一):使用.NET MAUI開發第一個安卓APP 對於工作多年的C#程式員來說,近來想嘗試開發一款安卓APP,考慮了很久最終選擇使用.NET MAUI這個微軟官方的框架來嘗試體驗開發安卓APP,畢竟是使用Visual Studio開發工具,使用起來也比較的順手,結合微軟官方的教程進行了安卓 ...
  • 前言 QuestPDF 是一個開源 .NET 庫,用於生成 PDF 文檔。使用了C# Fluent API方式可簡化開發、減少錯誤並提高工作效率。利用它可以輕鬆生成 PDF 報告、發票、導出文件等。 項目介紹 QuestPDF 是一個革命性的開源 .NET 庫,它徹底改變了我們生成 PDF 文檔的方 ...
  • 項目地址 項目後端地址: https://github.com/ZyPLJ/ZYTteeHole 項目前端頁面地址: ZyPLJ/TreeHoleVue (github.com) https://github.com/ZyPLJ/TreeHoleVue 目前項目測試訪問地址: http://tree ...
  • 話不多說,直接開乾 一.下載 1.官方鏈接下載: https://www.microsoft.com/zh-cn/sql-server/sql-server-downloads 2.在下載目錄中找到下麵這個小的安裝包 SQL2022-SSEI-Dev.exe,運行開始下載SQL server; 二. ...
  • 前言 隨著物聯網(IoT)技術的迅猛發展,MQTT(消息隊列遙測傳輸)協議憑藉其輕量級和高效性,已成為眾多物聯網應用的首選通信標準。 MQTTnet 作為一個高性能的 .NET 開源庫,為 .NET 平臺上的 MQTT 客戶端與伺服器開發提供了強大的支持。 本文將全面介紹 MQTTnet 的核心功能 ...
  • Serilog支持多種接收器用於日誌存儲,增強器用於添加屬性,LogContext管理動態屬性,支持多種輸出格式包括純文本、JSON及ExpressionTemplate。還提供了自定義格式化選項,適用於不同需求。 ...
  • 目錄簡介獲取 HTML 文檔解析 HTML 文檔測試參考文章 簡介 動態內容網站使用 JavaScript 腳本動態檢索和渲染數據,爬取信息時需要模擬瀏覽器行為,否則獲取到的源碼基本是空的。 本文使用的爬取步驟如下: 使用 Selenium 獲取渲染後的 HTML 文檔 使用 HtmlAgility ...
  • 1.前言 什麼是熱更新 游戲或者軟體更新時,無需重新下載客戶端進行安裝,而是在應用程式啟動的情況下,在內部進行資源或者代碼更新 Unity目前常用熱更新解決方案 HybridCLR,Xlua,ILRuntime等 Unity目前常用資源管理解決方案 AssetBundles,Addressable, ...
  • 本文章主要是在C# ASP.NET Core Web API框架實現向手機發送驗證碼簡訊功能。這裡我選擇是一個互億無線簡訊驗證碼平臺,其實像阿裡雲,騰訊雲上面也可以。 首先我們先去 互億無線 https://www.ihuyi.com/api/sms.html 去註冊一個賬號 註冊完成賬號後,它會送 ...
  • 通過以下方式可以高效,並保證數據同步的可靠性 1.API設計 使用RESTful設計,確保API端點明確,並使用適當的HTTP方法(如POST用於創建,PUT用於更新)。 設計清晰的請求和響應模型,以確保客戶端能夠理解預期格式。 2.數據驗證 在伺服器端進行嚴格的數據驗證,確保接收到的數據符合預期格 ...