番石榴Multimaps通配符putAll

时间:2015-02-02 20:56:15

标签: java generics guava

使用Guava的Multimap解决了泛型问题

class Foo{
    ...
    private Multimap<Baz,? extends Bar> stuff;
    ...

    public void overWriteStuff(Multimap<Baz,? extends Bar> newstuff){
         this.stuff.clear();
         this.stuff.putAll(newStuff);
    }
 }

对我来说这看起来非常简单,stuff和参数newstuff都有相同的类型,但我得到了与泛型有关的编译器异常:

The method putAll(Multimap<? extends Baz,? extends capture#8-of ? extends Bar>) in the type Multimap<Baz,capture#8-of ? extends Bar> is not applicable for the arguments (Multimap<Baz,capture#9-of ? extends Bar>)

有人能看到我的仿制品搞砸了吗?

2 个答案:

答案 0 :(得分:2)

原始声明中的?通配符与参数中的?通配符不匹配。它们可以是Bar(或Bar本身)的任何子类,并且它们不必匹配。

您需要在Foo上引入泛型类型参数来替换通配符,以便它们代表相同的类型。

class Foo<T extends Bar>{

在变量声明中:

private Multimap<Baz, T> stuff;

在方法参数中:

public void overWriteStuff(Multimap<Baz, T> newstuff){

顺便说一句,这与Java的泛型有关,但与Guava无关。我可以使用Map替换Multimap来复制错误。

答案 1 :(得分:2)

问题在于? extends Bar表示&{34>某些特定的(但未知)Bar&#34;的子类型。您不知道,对于您班级中的字段或您方法的参数,您可以知道多图包含的实际值类型。

例如,如果您有两个类Foo extends BarBlah extends Bar,则可以将Multimap<Baz, Foo>分配给stuff并将Multimap<Baz, Blah>传递给您的方法, newstuff。如果允许stuff.putAll(newstuff),那么您stuff是一个多图,声称其所有值都是Foo的实例,而实际上其中一些是Blah的实例{1}}。

也许你真的只想让stuff成为Multimap<Baz, Bar>?在这种情况下,它的值可以是任何类型Bar,您的方法将正常工作。正如@rgettman所提到的,另一个选择是引入一个类型变量T extends Bar,以确保stuffnewstuff的值都是{em>相同的子类型{ {1}};你做的取决于你在这里实际想要完成的事情。