2017-07-02 65 views
3
public static void reverse(List<?> list) 
{ 
List<Object> tmp = new ArrayList<Object>(list); 
for (int i = 0; i < list.size(); i++) 
{ 

list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ? 

} 

} 

我正在學習泛型。 我知道這一點:當使用通配符?被替換爲適當的類型。當reverse()方法被調用時?將被替換,因爲每個類型都是Object的子類型,所以不應該有錯誤。 我正在尋找一個水晶般清晰的解釋。請幫忙 。難以理解通配符

+1

'名單'是_unbounded_通配符。這意味着你只能在列表中插入'null'。 –

+0

https://docs.oracle.com/javase/tutorial/java/generics/unboundedWildcards.html –

+2

你誤解了'?'。它不會被取代。它標識一個* unknown *。 – Andreas

回答

1

您可以通過任何List<SomeType>reverse方法爲List<?> list參數,編譯器應該只允許你的SomeType元素添加到List

例如,它可能是一個List<String>,一個List<Ineger>,等...

因此list.set不能工作,因爲編譯器不知道的元素類型傳遞給方法的實際List<?> list支持。它不知道List<Object> tmp的元素起源於相同的list(因此可以安全地添加到它)。

寫你的方法正確的方法是定義一個泛型類型參數:

public static <T> void reverse(List<T> list) 
{ 
    List<T> tmp = new ArrayList<> (list); 
    for (int i = 0; i < list.size(); i++) { 
     list.set(i, tmp.get(list.size()-i-1)); 
    } 
} 

現在編譯器知道listtmp都包含相同類型的元素。

+0

Box box = new Box <>(「hello」)有什麼區別?和框 box = new Box (「hello」); 其中Box是class Box {T t; Box(T t){this.t = t; }} – steve

+0

@steve我相信前者會創建一個'Box '(因爲'new Box <>'的泛型參數的類型不能從'box'變量的類型推導出來),後者是a '箱子'。 – Eran

0

Generics work in this way

這裏:

public static void reverse(List<?> list) 

,因爲我們不知道是什麼的list代表元素類型,我們不能將對象添加到它。

這裏:

List<Object> tmp = new ArrayList<Object>(list); 
    ... 
list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ? 

您在List,在絕對可以包含與不同類型的元素添加Object秒。
在你的情況,這是不是你寫的情況:

List<Object> tmp = new ArrayList<Object>(list); 

但是編譯器不通過試圖理解你的代碼的邏輯做出例外。
因爲否則它應該檢查整個代碼,編譯器錯誤消息可能會非常複雜。
舉例來說,假設你在你的代碼中一次加入add tmp.set(0, "aa");

0

List<?>不是已知類型的列表,我們不知道在這個列表類型,仿製藥被引入刪除運行時類型轉換的異常,並給予安全。您無法將任何類型添加到包含undefined的集合中,因爲您會破壞它。例如這是否會被允許:

List<Dog> dogs = new ArrayList<>(Arrays.asList(new Dog("dog"))); 

    public doSomething(List<?> notKnownType) { 
     notKnownType.add(new Cat("cat")); 
// if this ok or not? <?> is not known type, all types have Object as parent let's add Cat 
    } 

    for (Dog dog : dogs) { 
     System.out.println(dog); //ClassCastException 
    } 

ClassCastExceptin因爲我們添加的貓犬和投每狗貓,在運行仿製藥不存在 和所有集合等包含對象。 這條線將是編譯類似的東西后:

for (Object dog : dogs) { 
    System.out.println((Dog) dog); //ClassCastExceptin 
} 

對於不允許這樣做,你不能夠添加一些未知類型的集合,並得到編譯這裏時錯誤list.set(i, tmp.get(list.size()-i-1)); // compile-time error , why ?