2015-04-22 112 views
3

我试图定义一个操作++为我定制Map类型是这样的:双通配符泛型类型错误

@Override 
public MutableMap<K, V> $plus$plus(Map<? extends K, ? extends V> map) 
{ 
    HashMap<K, V> copy = this.copy(); 
    map.$plus$plus$eq(map); 
    return copy; 
} 

++=运营商的定义是这样的:

public void $plus$plus$eq(Map<? extends K, ? extends V> map); 

然而,编译器在map.$plus$plus$eq(map);行抱怨,出现以下疯狂错误:

The method $plus$plus$eq(Map<? extends capture#10-of ? extends K, 
? extends capture#11-of ? extends V>) in the type 
Map<capture#10-of ? extends K,capture#11-of ? extends V> is not 
applicable for the arguments 
(Map<capture#12-of ? extends K,capture#13-of ? extends V>) 

正如你在这张截图看到,没有通过Eclipse的工作提供了,但单独的解决方案,甚至意义:

Eclipse Marker

我一直在Java泛型相当长一段时间的工作,现在,甚至已经开发我自己的自定义编程类型系统(我目前正在编码的库),但我从来没有像这样的错误。


编辑:有趣的是,铸造map参数的原始类型(Map)似乎来解决这个问题。

map.$plus$plus$eq((Map) map); 

但是,改变投地(Map<?, ?>)(这是Eclipse的第二个解决方案所做的)会导致类似的错误。

+0

你使用什么编译器? –

+0

以下哪些类是您的自定义类? Map是java.util.Map吗? –

+0

Eclipse月神服务版本2(4.4.2),目标兼容性1.8。 – Clashsoft

回答

4

它适用于原始类型Map,但是您失去了类型安全性。不要使用原始类型。它们只存在与Java 1.4及更早版本兼容,但没有泛型。

它不适用于通配符,因为编译器不知道通配符?代表什么类型的通配符。原因与您为什么不能call add() on a List<? extends T>的问题相同。

注意通配符不意味着其中关键的类型扩展K和值的类型扩展V你可以使用任何类型的对象。相反,这意味着你有一个映射,其中键是一些特定的,但未知的类型K,这些值是一些特定的,但未知的类型V。你不能在这样的地图上调用$plus$plus$eq,因为编译器不知道确切的类型,所以它不能检查它们。

原则上,您调用该方法的Map的通配符可能代表与您作为参数传递的Map的通配符不同的类型 - 即使您在此例中可以看到它们必须因为你在这种情况下使用相同的对象map

可以通过使用类型的参数,而不是通配符的修复:

@Override 
public <KK extends K, VV extends V> MutableMap<K, V> $plus$plus(Map<KK, VV> map) 
{ 
    HashMap<K, V> copy = this.copy(); 
    map.$plus$plus$eq(map); 
    return copy; 
} 
2

下面是也不编译的简化示例。

class Foo<T> { 

    void bar(Foo<? extends T> foo) { 
     foo.bar(foo); 
    } 
} 

假设foogoo有型Foo<? extends T>。这意味着foo的类型为Foo<U>,其中UT的子类型,而goo的类型是Foo<V>,其中V也是T的子类型。你不会指望foo.bar(goo)的工作,因为V可能不是U的子类型。因此,foo.bar(foo)也不能编译。这看起来很生气,因为foofoo是相同的实例,但参数是否适用仅取决于它们的编译时间类型。