Guava Multimaps 通配符 putAll

Guava Multimaps wildcard putAll

使用 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>)

谁能看到我的泛型问题在哪里?

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

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

class Foo<T extends Bar>{

在变量声明中:

private Multimap<Baz, T> stuff;

并且在方法参数中:

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

顺便说一句,这与 Java 的泛型有关,但与 Guava 无关。我可以用 Map 替换 Multimap.

来复制错误

问题是 ? extends Bar 意味着 "some specific (but unknown) subtype of Bar"。您不知道,对于 class 中的字段或您的方法的参数,multimap 持有什么实际类型的值。

例如,如果您有两个 classes Foo extends BarBlah extends Bar,您可以将 Multimap<Baz, Foo> 分配给 stuff 并传递 Multimap<Baz, Blah> 作为 newstuff 到您的方法。如果 stuff.putAll(newstuff) 被允许,那么 stuff 是一个多重映射,声称其所有值都是 Foo 的实例,而实际上其中一些值是 [=21] 的实例=].

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