java - 提取具有通用返回类型的表达式后类型不匹配

标签 java generics types refactoring capture

在执行提取表达式重构时,我偶然发现了 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>>

由于原始代码确实可以编译,所以我有点不解。也许有人可以帮助我并给出解释?提前致谢!

最佳答案

让我们先回顾一下原始出处:

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 相同的键值(来自循环)。由于不能百分百确定这些类型是否兼容,编译器会引发编译时错误,**即使**您可能确信这些类型在运行时是相同的。

关于java - 提取具有通用返回类型的表达式后类型不匹配,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31205972/

相关文章:

java - 将 Markdown 文件解析为 Java 中的 JSON 对象

java - 使用 picasso 将图像大小调整为全宽和固定高度

java - 检索 JBoss 上的数据源统计信息

scala - Scala类参数化中附加冒号的含义

arrays - 是否可以在 Swift 中将子类型的元组添加到类型的元组数组中?

typescript :映射类型中的索引签名

java - 设置 log4j2 日志文件的相对路径

typescript - 泛型函数子类型约束错误和混淆

c# - 使用泛型类型 'System.Collections.Generic.List<T>' 需要 1 个类型参数

Haskell 多态解构