2013-04-25 24 views
1

我哈瓦一個列表包含今後的任務,未來的類型是未知的,所以我創建通配符類型?名單,但是當我一個元素添加到列表中,編譯錯誤發生。添加到wildchar表原因的元素編譯錯誤

這是代碼:

private List<Pair<String, Future<?>>> futureTasks = Collections.synchronizedList(
     new ArrayList<Pair<String, Future<?>>>(8)); 

// taskId is a string 
futureTasks.add(Pair.makePair(taskId, getExecutors().submit(
    new Callable<String>() { 
     public String call() { 
      try { 
       return exportAccountSrcTask(tmpFile); // return a string 
      } catch (Exception e) { 
       logger.error("failed to export account src", e); 
      } 
      return null; 
    }})) 
); 

編譯器錯誤:

The method add(Pair<String,Future<?>>) in the type List<Pair<String,Future<?>>> is not applicable for the arguments (Pair<String,Future<String>>)

+0

爲什麼不能將它聲明爲'List >>'? – 2013-04-25 03:36:47

+0

未來可能不會是字符串 – jamee 2013-04-25 03:38:29

+0

然後聲明它爲'List >>'。至於你爲什麼不能用通配符'.add()':http://stackoverflow.com/q/3716920/和http://stackoverflow.com/q/69702/ – 2013-04-25 03:39:22

回答

5

你得到一個錯誤,因爲Pair<String, Future<String>>不是Pair<String, Future<?>>。泛型類型不是協變的。

但是,您可以爲List<Pair<String, ? extends Future<?>>>futureTasks。然後你就可以添加一個Pair<String, Future<String>>它。

編輯:

爲了解釋這更好的,想嘗試分配對象的變量,而不是將其添加到列表中。如果我們有一個List<T>,我們如果是一個T只添加一個對象。因此,這是真的了同樣的情況:

Pair<String, Future<String>> pairOfStringAndFutureOfString; 
Pair<String, Future<?>> pairOfStringAndFutureOfSomething; 

// incompatible types 
pairOfStringAndFutureOfSomething = pairOfStringAndFutureOfString; 

再次,這是不允許的,因爲泛型不是協變。爲什麼?試想,如果他們是會發生什麼:

Future<Integer> futureOfInt; 
Future<?> futureOfSomething; 
futureOfSomething = futureOfInt; // a future of int is a future of something 

Pair<String, Future<String>> pairOfStringAndFutureOfString; 
Pair<String, Future<?>> pairOfStringAndFutureOfSomething; 

// pretend this is legal 
pairOfStringAndFutureOfSomething = pairOfStringAndFutureOfString; 

// danger! 
pairOfStringAndFutureOfSomething.setRight(futureOfSomething); 
Future<String> futureOfString = pairOfStringAndFutureOfString.getRight(); 

//sometime later... 
String string = futureOfString.get(); //ClassCastException 

我們得到了futureOfString指向的東西,實際上是一個Future<Integer>。但是這甚至不會立即導致ClassCastException,因爲由於類型擦除,JVM只看到Future s。這種情況被稱爲「堆污染」 - 一個變量指向一個它不應該被允許的對象。實際運行時錯誤只發生在我們嘗試解包futureOfString時發生。

所以這解釋了爲什麼泛型不是協變。讓我們看看解決方法:

Pair<String, ? extends Future<?>> 
pairOfStringAndSomethingThatIsAFutureOfSomething; 

該變量名稱是滿口的,但我希望它能夠準確描述這裏發生了什麼。之前,第二類型的論據是正是Future<?>。現在,我們說這是「一些未知類型,它或擴展Future<?>。例如,它可能是Future<?>,也可能是Future<String>,它甚至可以是MySpecialFuture<Integer>

我們主動放棄了一些資料關於這個變量,以放鬆身心什麼可以分配給它的類型現在,這是合法的:

pairOfStringAndSomethingThatIsAFutureOfSomething = pairOfStringAndFutureOfString; 

編譯器通過阻止這種未知類型被防止早期的「堆污染」情景「消費「:

//compiler error - nothing can be legally passed into setRight 
pairOfStringAndSomethingThatIsAFutureOfSomething.setRight(futureOfSomething); 

要了解有關這些限制的更多信息,請參閱此帖:What is PECS (Producer Extends Consumer Super)?

+1

是的,它的工作,謝謝,但爲什麼? – jamee 2013-04-25 06:29:39

+0

@jamee看到我的編輯,讓我知道你是否還有其他問題。 – 2013-04-25 15:46:40

+0

似乎我可以將Pair >和Pair >添加到List >>,並且沒有編譯錯誤。 – jamee 2013-04-26 02:41:15

相關問題