2010-11-16 26 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找到一个可以与你的例子相关的小节选。