2016-12-03 22 views
1

幾年前,當Java7已經發布了一年左右時,我已經從C#開始回到Java - 在某些方面,Java通用對我來說似乎很奇怪。'Java操作符'缺少Java中變量的定義嗎?

有一個我回來了一遍又一遍,這兩個答案的普及看到...

  1. Difference between <? super T> and <? extends T> in Java
  2. What is PECS (Producer Extends Consumer Super)?

...看來很多人們(包括我)「自然地」會期望與「泛型集合」聲明中的語法不同的行爲。考慮下面的代碼示例...

注:建築正確性超出範圍 - 假設baseClassesStorage應該可用於都得到/添加在外界

public class DummyClass { 

    public static class BaseClass {} 

    public static interface ListOfAtLeastBaseClasses<T extends BaseClass> extends List<T> {} 

    public ListOfAtLeastBaseClasses<?> baseClassesStorage; 

    public void addToStorage(BaseClass item) { 
     baseClassesStorage.add(item); 
    } 
} 

...典型的程序員從非Java世界將假設ListOfAtLeastBaseClasses<?> baseClassesStorage說:「這是從BaseClass衍生物品存儲」,但這個樣本的編譯在baseClassesStorage.add(item)失敗,以下錯誤:

C:\Temp\...\DummyClass.java:14: error: no suitable method found for add(BaseClass) 
     baseClassesStorage.add(item); 
         ^
    method Collection.add(CAP#1) is not applicable 
     (argument mismatch; BaseClass cannot be converted to CAP#1) 
    method List.add(CAP#1) is not applicable 
     (argument mismatch; BaseClass cannot be converted to CAP#1) 
    where CAP#1 is a fresh type-variable: 
    CAP#1 extends BaseClass from capture of ? 

這種行爲的原因在兩個above mentioned answers中描述。

但是,我應該怎麼做才能實現我的用例以'正確'和'優雅'的方式?

選項我知道有關:

  1. 看來,「正確的Java方法」的聲明變量 public ListOfAtLeastBaseClasses<BaseClass> baseClassesStorage; 但這樣一來我確實有下界是「名單的冗餘定義' - 它已經在ListOfAtLeastBaseClasses類的'合同'中定義。這裏的另一個問題 - 如果在某個時間點,我想要改變ListOfAtLeastBaseClasses類的下限,那麼我將需要遍歷所有這種類型的成員變量並改變它們的定義:(。

  2. 使用'raw 「類型 public ListOfAtLeastBaseClasses baseClassesStorage; 這將編譯,但有效去除類型檢查和編譯過程中產生不必要的警告。

  3. ...還有什麼是可能的?...

    • ListOfAtLeastBaseClasses<?> baseClassesStorage; - 是Java
    • 不同的事情
    • ListOfAtLeastBaseClasses<> baseClassesStorage; - 編譯出錯
    • ListOfAtLeastBaseClasses<*> baseClassesStorage; - 編譯出錯

回答

2

看來, '正確的Java方法' 是聲明變量as

public ListOfAtLeastBaseClasses<BaseClass> baseClassesStorage; 

但這種方式實際上我的下冗餘定義的約束是「列表」,

不是真的的。當你定義泛型類型,你說這個類的用戶將能夠聲明變量像

ListOfAtLeastBaseClasses<Foo> listOfFoo; 
ListOfAtLeastBaseClasses<Bar> listOfBar; 

其中Foo和Bar必須的BaseClass的子類。 BaseClass是一個上限。但泛型類型的用戶可以選擇列表來限制更多,因此只接受Foo或Bar的實例。

當作爲

ListOfAtLeastBaseClasses<BaseClass> 

你選擇做,可以接受任何類型的BaseClass實例的列表中,您聲明您的列表。

我們可以想象一個特殊的語法來說ListofAtLeastBaseClasses<TheDefinedUpperBound>,但這不是鑽石操作員的用處,特殊的語法IMO會引入不必要的複雜性。

+0

你能告訴我更多關於'不必要的複雜性'的含義嗎?我問的是因爲對於我聲明數百個變量爲「ListOfAtLeastBaseClasses 」比「ListOfAtLeastBaseClasses <*>」或「ListOfAtLeastBaseClasses <>」更復雜。不久之後 - 當前的鑽石操作員在創建實例時刪除類型定義冗餘。我認爲同樣消除'定義變量'的冗餘會降低代碼的複雜性。 –

+0

泛型類型的大多數用法在於使用比上限更具體的類型(否則在首先將類型設置爲泛型的時候沒有多少意義)。例如:我不記得上次我使用List 。添加另一種語法會使泛型更復雜,並且不會爲我們現在已經可以做的事添加任何東西。鑽石操作員是不同的,因爲它解決了非常非常常見的冗長問題。但無論如何,您和我都不能更改語言,所以... –

+0

更不用說您的提議會使代碼不易讀。要知道Foo中的實際類型foo <*> foo = someMethod()'我必須查看Foo的類型定義才能知道上限是什麼。 –