2015-06-10 34 views
13

參考:Wildcard Capture Helper Methods爲什麼要使用通配符捕獲方法?

它說創建一個輔助方法來捕獲通配符。

public void foo(List<?> i) { 
    fooHelper(i); 
}   
private <T> void fooHelper(List<T> l) { 
    l.set(0, l.get(0)); 
} 

僅僅在下面使用這個函數不會產生任何編譯錯誤,並且似乎以同樣的方式工作。我不明白的是:爲什麼你不使用這個,並避免使用助手?

public <T> void foo(List<T> l) { 
    l.set(0, l.get(0)); 
} 

我認爲這個問題真的可以歸結爲:通配符和泛型之間有什麼區別?所以,我去了這個:difference between wildcard and generics。 它說,使用類型參數:

1) If you want to enforce some relationship on the different types of method arguments, you can't do that with wildcards, you have to use type parameters.

但是,是不是正是與助手功能通配符實際上是在做什麼?它是不是通過設置和獲取未知值來強制執行不同類型的方法參數的關係?

我的問題是:如果你有定義的東西,需要不同類型的方法參數的個數有關係,那麼爲什麼首先使用通配符,然後使用一個輔助的功能呢?

好像納入通配符哈克的方式。

+1

不,我不是看過那個 –

回答

7

在那是因爲List.set(int, E)方法要求是相同的列表類型的類型這種特殊情況。

如果沒有輔助方法,編譯器不知道?是同爲List<?>get(int)返回,所以你得到一個編譯錯誤:

The method set(int, capture#1-of ?) in the type List<capture#1-of ?> is not applicable for the arguments (int, capture#2-of ?) 

隨着輔助方法,你告訴編譯器,類型是一樣的,我只是不知道類型是什麼。

那麼,爲什麼有非helper方法?

仿製藥並沒有出臺,直到Java 5的所以有大量的代碼在那裏,早於仿製藥。 Java之前的版本5 List現在是List<?>,所以如果您嘗試在通用感知編譯器中編譯舊代碼,那麼如果您無法更改方法簽名,則必須添加這些幫助器方法。

+1

對,但是如果你忽略通配符函數,並且只使用助手,你仍然可以得到正確的輸出,而不會出現任何編譯錯誤。 –

+0

@BrandonLing是的,我會更新我的答案。 – dkatzel

+0

我明白爲什麼編譯器不理解沒有輔助函數的通配符,但pre-java5部分回答了我的問題。謝謝。 –

2

我同意:刪除輔助方法並輸入公共API。沒有理由不這樣做,也沒有理由。

只是總結與通配符版本助手的需要:雖然這是明顯地向我們人類,編譯器不知道從l.get(0)返回未知類型是相同未知類型列表本身。即它並不是因爲調用的參數來自與目標相同的列表對象,所以它必須是安全的操作。它只注意到從get()返回的類型是未知的,並且目標列表的類型是未知的,並且兩個未知數不保證是相同的類型。

4

你是正確的,我們不必使用通配符版本。

它歸結到API看起來/感覺「更好」,這是主觀的

void foo(List<?> i) 
<T> void foo(List<T> i) 

我會說的第一個版本更好。

如果有邊界

void foo(List<? extends Number> i) 
<T extends Number> void foo(List<T> i) 

首屆版本看起來更加緊湊;類型信息都在一個地方。

在這個時候,通配符是常用的方式,程序員更熟悉它。

在JDK方法定義中有一個lot通配符,特別是在java8引入lambda/Stream之後。無可否認,它們非常醜陋,因爲我們沒有差異類型。但想一想,如果我們將所有通配符擴展到變量類型,它會變得多麼糟糕。

+2

@SotiriosDelimanolis - 我從這個問題得到了不同的解讀 - OP詢問''版本有什麼意義,而''版本工作得很好。 – ZhongYu

+1

OP知道''從呼叫方的作品;但實施者的方面需要一個''幫手。 OP認爲''版本是一個多餘的中間人,問爲什麼我們不公開''版本。 – ZhongYu

相關問題