在执行提取表达式重构时,我偶然发现了Eclipse 4.4和Java 8 build 45中的一些奇怪的行为。以下示例显示了应用提取重构之前的原始和无错误代码:
import java.util.Map;
import java.util.Set;
public class MyMap<K, V> {
public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
for (Map.Entry<? extends K, ? extends V> entry : mapToCopy.entrySet()) {
}
}
}
Eclipse重构的结果如下所示,并导致下面的错误消息引用了循环声明中entrySet
的读访问权:
public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
Set<?> entrySet = mapToCopy.entrySet();
for (Map.Entry<? extends K, ? extends V> entry : entrySet) {
^^^^^^^^
}
}
Type mismatch: cannot convert
from element type capture#3-of ?
to Map.Entry<? extends K,? extends V>
我将entrySet
声明的类型更改为Set<Map.Entry<? extends K, ? extends V>>
。这一次,错误在声明的初始化程序中指出,说:
public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
Set<Map.Entry<? extends K, ? extends V>> entrySet = mapToCopy.entrySet();
^^^^^^^^^^^^^^^^^^^^
for (Map.Entry<? extends K, ? extends V> entry : entrySet) {
}
}
Type mismatch: cannot convert
from Set<Map.Entry<capture#1-of ? extends K,capture#2-of ? extends V>>
to Set<Map.Entry<? extends K,? extends V>>
由于原始代码编译,我有点困惑。也许有人可以帮助我并给出解释?提前谢谢!
答案 0 :(得分:0)
让我们先回顾原始资料来源:
public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
for (Map.Entry<? extends K, ? extends V> entry : mapToCopy.entrySet()) {
}
}
在内部(和运行时),这将被编译并将作为:
public void putAll(final Map mapToCopy) {
for (Iterator<Map.Entry> iterator = mapToCopy.iterator; iterator.hasNext();) {
}
}
其中? extends K
和? extends V
将替换为类型擦除后的一些实际类型。编译器将知道这些类型是什么,并且不会因类型不兼容而引发Exception
。
另一方面,如果您将源重构为此,
public void putAll(final Map<? extends K, ? extends V> mapToCopy) {
Set<Entry<? extends K, ? extends V>> entrySet = mapToCopy.entrySet();
^^^^^^^^
for (Map.Entry<? extends K, ? extends V> entry : entrySet) {
}
}
然后编译器将没有证据表明entrySet
与Map.Entry<? extends K, ? extends V>
保持类型相同,只是因为通配符(?
)始终代表某些东西未知,即无法保证entrySet
条目键值中的通配符与entry
&#39;相同。 s键值(来自循环)。不是百分之百确定类型是兼容的,编译器会引发编译时错误,**即使**你可能有信心这些类型在运行时是相同的。