泛型通配符捕獲和Helper方法
在某些情況下,編譯器會(huì)推斷出通配符的類型,例如,列表可以定義為List>,但是在評(píng)估表達(dá)式時(shí),編譯器會(huì)從代碼中推斷出特定類型,此場(chǎng)景稱為通配符捕獲。
在大多數(shù)情況下,你不必?fù)?dān)心通配符捕獲,除非你看到包含短語(yǔ)“capture of”的錯(cuò)誤消息。
WildcardError示例在編譯時(shí)產(chǎn)生捕獲錯(cuò)誤:
import java.util.List; public class WildcardError { void foo(List> i) { i.set(0, i.get(0)); } }
在此示例中,編譯器將i輸入?yún)?shù)處理為Object類型,當(dāng)foo方法調(diào)用List.set(int, E)時(shí),編譯器無(wú)法確認(rèn)插入到列表中的對(duì)象的類型,并且會(huì)產(chǎn)生錯(cuò)誤,發(fā)生此類錯(cuò)誤時(shí),通常意味著編譯器認(rèn)為你為變量分配了錯(cuò)誤的類型,出于這個(gè)原因,泛型被添加到Java語(yǔ)言中 — 在編譯時(shí)強(qiáng)制執(zhí)行類型安全。
由Oracle的JDK 7 javac實(shí)現(xiàn)編譯時(shí),WildcardError示例生成以下錯(cuò)誤:
WildcardError.java:6: error: method set in interface Listcannot 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í)行安全操作,那么如何解決編譯器錯(cuò)誤?你可以通過(guò)編寫捕獲通配符的私有Helper方法來(lái)修復(fù)它,在這種情況下,你可以通過(guò)創(chuàng)建私有Helper方法fooHelper來(lái)解決此問(wèn)題,如WildcardFixed中所示:
public class WildcardFixed { void foo(List> i) { fooHelper(i); } // Helper method created so that the wildcard can be captured // through type inference. privatevoid fooHelper(List l) { l.set(0, l.get(0)); } }
由于Helper方法,編譯器使用推斷來(lái)確定T是調(diào)用中的CAP#1(捕獲變量),該示例現(xiàn)在成功編譯。
按照慣例,Helper方法通常命名為originalMethodNameHelper。
現(xiàn)在考慮一個(gè)更復(fù)雜的例子,WildcardErrorBad:
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)); // expected a CAP#1 extends Number, // got a CAP#2 extends Number; // same bound, but different types l2.set(0, temp); // expected a CAP#1 extends Number, // got a Number } }
在這個(gè)例子中,代碼正在嘗試不安全的操作,例如,考慮以下對(duì)swapFirst方法的調(diào)用:
Listli = Arrays.asList(1, 2, 3); List ld = Arrays.asList(10.10, 20.20, 30.30); swapFirst(li, ld);
List
使用Oracle的JDK javac編譯器編譯代碼會(huì)產(chǎn)生以下錯(cuò)誤:
WildcardErrorBad.java:7: error: method set in interface Listcannot be applied to given types; l1.set(0, l2.get(0)); // expected a CAP#1 extends Number, ^ required: int,CAP#1 found: int,Number reason: actual argument Number 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 Number from capture of ? extends Number WildcardErrorBad.java:10: error: method set in interface List cannot be applied to given types; l2.set(0, temp); // expected a CAP#1 extends Number, ^ required: int,CAP#1 found: int,Number reason: actual argument Number 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 Number from capture of ? extends Number WildcardErrorBad.java:15: error: method set in interface List 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 ? 3 errors
這里沒(méi)有Helper方法來(lái)解決這個(gè)問(wèn)題,因?yàn)榇a根本就是錯(cuò)誤的。
上一篇:泛型通配符文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。
轉(zhuǎn)載請(qǐng)注明本文地址:http://m.hztianpu.com/yun/72942.html
Java? 教程 Java教程是為JDK 8編寫的,本頁(yè)面中描述的示例和實(shí)踐沒(méi)有利用在后續(xù)版本中引入的改進(jìn)。 Java教程是希望使用Java編程語(yǔ)言創(chuàng)建應(yīng)用程序的程序員的實(shí)用指南,其中包括數(shù)百個(gè)完整的工作示例和數(shù)十個(gè)課程,相關(guān)課程組被組織成教程。 覆蓋基礎(chǔ)知識(shí)的路徑 這些教程以書籍的形式提供,如Java教程,第六版,前往Amazon.com購(gòu)買。 入門 介紹Java技術(shù)和安裝Java開(kāi)發(fā)軟件并使用...
泛型的限制 要有效地使用Java泛型,必須考慮以下限制: 無(wú)法使用基元類型實(shí)例化泛型類型 無(wú)法創(chuàng)建類型參數(shù)的實(shí)例 無(wú)法聲明類型為類型參數(shù)的靜態(tài)字段 無(wú)法對(duì)參數(shù)化類型使用強(qiáng)制類型轉(zhuǎn)換或instanceof 無(wú)法創(chuàng)建參數(shù)化類型的數(shù)組 無(wú)法創(chuàng)建、捕獲或拋出參數(shù)化類型的對(duì)象 無(wú)法重載將每個(gè)重載的形式參數(shù)類型擦除為相同原始類型的方法 無(wú)法使用基元類型實(shí)例化泛型類型 考慮以下參數(shù)化類型: class P...
泛型通配符 在泛型代碼中,稱為通配符的問(wèn)號(hào)(?)表示未知類型,通配符可用于各種情況:作為參數(shù)、字段或局部變量的類型,有時(shí)作為返回類型(盡管更好的編程實(shí)踐是更加具體),通配符從不用作泛型方法調(diào)用、泛型類實(shí)例創(chuàng)建或超類型的類型參數(shù)。 以下部分更詳細(xì)地討論通配符,包括上界通配符、下界通配符和通配符捕獲。 上界通配符 你可以使用上界通配符來(lái)放寬對(duì)變量的限制,例如,假設(shè)你要編寫一個(gè)適用于List、List和...
摘要:好了,有了這樣的背景知識(shí),我們可以來(lái)看一下上界通配了,在中,可以使用來(lái)界定一個(gè)上界,的意思是所有屬于的子類,是上界,不能突破天界啊,我們具體化一下,的意思就是,所有的子類都可以匹配這個(gè)通配符。 1、上界通配符 首先,需要知道的是,Java語(yǔ)言中的數(shù)組是支付協(xié)變的,什么意思呢?看下面的代碼: static class A extends Base{ void f(...
摘要:靜態(tài)變量是被泛型類的所有實(shí)例所共享的。所以引用能完成泛型類型的檢查。對(duì)于這個(gè)類型系統(tǒng),有如下的一些規(guī)則相同類型參數(shù)的泛型類的關(guān)系取決于泛型類自身的繼承體系結(jié)構(gòu)。事實(shí)上,泛型類擴(kuò)展都不合法。 前言 和C++以模板來(lái)實(shí)現(xiàn)靜多態(tài)不同,Java基于運(yùn)行時(shí)支持選擇了泛型,兩者的實(shí)現(xiàn)原理大相庭徑。C++可以支持基本類型作為模板參數(shù),Java卻只能接受類作為泛型參數(shù);Java可以在泛型類的方法中取得...
閱讀 2232·2021-09-04 16:40
閱讀 1540·2021-08-13 15:07
閱讀 3670·2019-08-30 15:53
閱讀 3269·2019-08-30 13:11
閱讀 1149·2019-08-29 17:22
閱讀 1866·2019-08-29 12:47
閱讀 1540·2019-08-29 11:27
閱讀 2338·2019-08-26 18:42