2010-11-16 49 views
0

我無法通過通配符理解Java泛型的更精細的點。具體來說,爲什麼不編譯。帶通配符的Java非泛型不編譯

public class Test { 

    abstract class Function<A, B> { 
     abstract B call(A a); 
    } 

    interface PropertyType { 
     String bubbles(); 
    } 

    class Apartment implements PropertyType { 
     @Override 
     public String bubbles() { 
      return "bubbles"; 
     } 
    } 

    public void invokeFunctionOnAList() { 
     List<Apartment> apts = new ArrayList<Apartment>(); 
     functionLoop(apts, new Function<Apartment, String>() { 

      @Override 
      String call(Apartment a) { 
       return a.bubbles(); 
      } 
     }); 
    } 

    public void functionLoop(List<? extends PropertyType> list, Function<? extends PropertyType, String> t) { 
     for (PropertyType p : list) { 
      t.call(p); 
     } 
    } 
} 
+0

我可以看到這個問題,大多數Java編譯器都會對它做出相當明確的說明。你會得到什麼錯誤? – PaulJWilliams 2010-11-16 11:47:05

+3

如果您要報告某些內容無法編譯,您應該*總是*包含錯誤消息和位置。 – 2010-11-16 11:47:13

回答

1

您的編譯器不知道您是否在列表和函數中使用相同的類型。所以你必須告訴他這一點。

試試這個:

public <C extends PropertyType>void functionLoop(
         List<C> list, Function<C, String> t) { 
    for (C p : list) { 
    t.call(p); 
    } 
} 
+0

哦,我明白了,因爲List的子類型不需要是Function的子類型? – monkjack 2010-11-16 12:08:41

+0

是的,列表中的對象類型必須與Function中的調用方法中的參數類型相同。 – 2010-11-16 12:13:09

0

因爲call(Apartment a)應該得到Apartment對象作爲參數,你傳遞一個PropertyType對象。儘管Apartment是-a PropertyType,但是PropertyType是-IN-NOT-a Appartment

3

最形式上正確的方式把這些代碼實際上是

public <C extends PropertyType> void functionLoop(
     List<C> list, Function<? super C, String> t) { 
    for (C p : list) { 
     t.call(p); 
    } 
} 

我發現仿製藥的最好的解釋是在「有效的Java」由Joshua布洛赫。你可以在這個presentation找到一個可以與你的例子相關的小節選。