我发现Eclipse和javac之间在以下代码中的行为存在重大差异:
public class TestIncompatibleTypes {
private static <V> void libraryMethod(Class<? extends List<V>> in) {}
public static void main(String[] args) {
// Eclipse warns about 'Unchecked cast'
// Maven fails with 'incompatible types'
Class<? extends List<String>> l = (Class<? extends List<String>>) ArrayList.class;
libraryMethod(l);
}
}
Eclipse会发布未经检查的广告素材&#39;警告上面的代码,但它成功编译。 Javac生成错误:
$ java -version
openjdk version "1.8.0_72-internal"
OpenJDK Runtime Environment (build 1.8.0_72-internal-b15)
OpenJDK 64-Bit Server VM (build 25.72-b15, mixed mode)
$ javac -version
javac 1.8.0_72-internal
$ javac -source 8 TestIncompatibleTypes.java
TestIncompatibleTypes.java:13: error: incompatible types: Class<ArrayList> cannot be converted to Class<? extends List<String>>
Class<? extends List<String>> l = (Class<? extends List<String>>) ArrayList.class;
^
1 error
任何人都可以解释为什么javac不允许演员?我的理解是它们在类型擦除后应该完全等效。
是否有解决方法可以在两个编译器上进行编译?
答案 0 :(得分:3)
是否有解决方法可以在两个编译器上进行编译?
Class<? extends List<String>> clazz;
// casting to interim type
clazz = (Class<? extends List<String>>) (Class<? extends List>) ArrayList.class;
// raw types .......
clazz = (Class) ArrayList.class;
无论其!这段代码值得解释它为何起作用以及何时可能不安全:
java.util.ArrayList
对其类型变量没有特别限制。java.lang.Class
是不可变的,只能用于创建新实例。如果您使用除ArrayList
和Class
之外的其他类型,则此相同的转换可能会导致堆污染。丢掉重要信息:
class IntegerList extends ArrayList<Integer> {}
// now we can create a new instance and put String in a List<Integer>
Class<? extends List<String>> clazz =
(Class<? extends List<String>>) (Class<? extends List>) IntegerList.class;
(我还要注意,使用ArrayList.class
仍然可能导致堆污染,而我对它的思考还不够。)
在Java 8中,我们应该首选lambda来实现创建,这可以避免这个问题:
static <V> void libraryMethod(Supplier<? extends List<V>> in) {}
void somewhere() {
Supplier<? extends List<String>> supplier = ArrayList::new;
libraryMethod(supplier);
}
当然,如果由于某些原因你无法使用它,那么Class
偶尔会遇到麻烦的事情。
任何人都可以解释为什么javac不允许演员?
Java不允许&#34;横向&#34;演员,例如:
Number n = ...;
String s = (Number) n; // compiler error
简短的解释是存在这样的子类型关系:
Class<? extends List>
╱ ╲
Class<? extends List<String>> Class<ArrayList>
两者都是Class<? extends List>
的子类型,并且没有一个是子类型,也不是另一个的超类型。
答案 1 :(得分:1)
您似乎正在向Class<ArrayList>>
投放Class<? extends List<String>>
,但ArrayList
类没有那种通用。我不确定您的<String>
Class<? extends List>
通用