tte*_*rag 11 java generics type-inference javac java-8
这是我正在使用的代码的最小示例:
public class Temp {
enum SomeEnum {}
private static final Map<SomeEnum, String> TEST = new EnumMap<>(
Arrays.stream(SomeEnum.values())
.collect(Collectors.toMap(t -> t, a -> "")));
}
Run Code Online (Sandbox Code Playgroud)
编译器输出是:
Temp.java:27: error: cannot infer type arguments for EnumMap<>
private static final Map<SomeEnum, String> TEST = new EnumMap<>(Arrays.stream(SomeEnum.values())
^
Run Code Online (Sandbox Code Playgroud)
我发现,这可以通过更换被合作周围t -> t有Function.identity()或(SomeEnum t) -> t,但我不理解为什么是这样的情况.javac有什么限制导致这种行为?
我最初在java 8中发现了这个问题,但已经证实它仍然发生在java 11编译器中.
我们可以进一步简化示例:
声明一个类似的方法
static <K,V> Map<K,V> test(Map<K,? extends V> m) {
return Collections.unmodifiableMap(m);
}
Run Code Online (Sandbox Code Playgroud)
该声明
Map<SomeEnum, String> m = test(Collections.emptyMap());
Run Code Online (Sandbox Code Playgroud)
可以编译没有问题.现在,当我们将方法声明更改为
static <K extends Enum<K>,V> Map<K,V> test(Map<K,? extends V> m) {
return Collections.unmodifiableMap(m);
}
Run Code Online (Sandbox Code Playgroud)
我们得到编译器错误.这表明将流表达式包装在new EnumMap<>(…)和表达式之间的区别new HashMap<>(…)在于键类型的类型参数声明,因为EnumMap's键类型参数已被声明为K extends Enum<K>.
它似乎与声明的自引用性质有关,例如K extends Serializable,同时不会引起错误K extends Comparable<K>.
虽然javac从Java 8到Java 11的所有版本都失败了,但行为并不像看起来那么一致.当我们将声明更改为
static <K extends Enum<K>,V> Map<K,V> test(Map<? extends K,? extends V> m) {
return Collections.unmodifiableMap(m);
}
Run Code Online (Sandbox Code Playgroud)
代码可以在Java 8下再次编译,但仍然在Java 9到11中失败.
对我来说,这是不合逻辑的是,编译器推断SomeEnum的K(这将匹配绑定Enum<K>),并String为V,但没有在bound已指定推断这些类型K.所以我认为这是一个错误.我不能排除在规范深度的某处有一个声明,它允许得出结论编译器应该以这种方式运行,但如果是这样,那么规范也应该被修复.
正如评论部分中的其他人所说,这个代码可以用Eclipse编译而没有问题.
| 归档时间: |
|
| 查看次数: |
258 次 |
| 最近记录: |