这是简单的代码
import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.Map;
public class SimpleTest {
public static void main(String[] args) {
final ArrayList<Map<String, Object>> maps = newArrayList(
createMap("1", "a", Collections.EMPTY_MAP, Collections.EMPTY_MAP),
createMap("2", "b", Collections.EMPTY_MAP, Collections.EMPTY_MAP),
createMap("3", "c", Collections.EMPTY_MAP, Collections.EMPTY_MAP)
);
System.out.println(" maps = " + maps);
}
public static Map<String, Object> createMap(String value1, String value2, Map<String, Object> object1, Map<String, Object> object2) {
Map<String, Object> map = new HashMap<>();
map.put("value1", value1);
map.put("value1", value1);
map.put("object1", object1);
map.put("object2", object2);
return map;
}
public static <E> ArrayList<E> newArrayList(E... elements) {
ArrayList<E> list = new ArrayList<E>(elements.length);
Collections.addAll(list, elements);
return list;
}
}
当JAVA_HOME指向JDK 8并且我使用javac -source 1.7 SimpleTest.java
时,我得到了
SimpleTest.java:9: error: incompatible types: ArrayList<Map> cannot be converted to ArrayList<Map<String,Object>>
final ArrayList<Map<String, Object>> maps = newArrayList(
^
当我使用-source 1.8
或没有-source
选项时,一切正常。现在,当JAVA_HOME指向JDK 7时,代码总是编译我是否使用-source 1.7
。
最初这个问题是关于一个软件,其中POM文件的<source>
和<target>
设置为1.7
并且构建在JDK 8上失败但在JDK 7上没问题。
现在提出问题 - 导致它发生的原因是什么?在我看来,这是某种主要的忽视。为什么在source
设置为1.7
的情况下编译JDK 8会失败?
答案 0 :(得分:4)
您可以将代码简化为不需要第三方库的自包含示例:
public class Test2 {
@SafeVarargs
static <T> ArrayList<T> newArrayList(T... arg) {
return new ArrayList<T>(Arrays.asList(arg));
}
private final List<Map<String, Object>> maps = newArrayList(
createMap(null, Collections.EMPTY_MAP)
);
public static Map<String, Object> createMap(String id, Map<String,String> m) {
return null;
}
}
这可以使用jdk1.7中的javac
进行编译,但不能使用javac
使用jdk1.8中的-source 1.7
进行编译。
这里的要点是来自jdk1.8的javac
仍然是与前一版本中包含的编译器不同的编译器,并且选项-source 1.7
并不告诉它模仿旧实现的行为但是与Java 7 规范兼容。如果旧编译器有错误,则较新的编译器不必尝试重现该错误。
由于代码使用Collections.EMPTY_MAP
而非Collections.<String,String>emptyMap()
,原始类型Map
将传递给createMap
,使其成为具有原始结果类型{{的未经检查的调用1}}。
所选方法的结果类型确定如下:
如果声明所选方法的返回类型为void,则结果为void。
否则,如果该方法需要未经检查的转换,则结果类型是方法声明的返回类型的擦除(§4.6)。
...
似乎这种行为还没有(完全)在jdk1.7的Map
中实现。有趣的是,它在添加类型参数(如
javac
使其成为通用方法。然后,jdk1.7将产生相同的错误。但引用的规则适用于所有方法调用。
相比之下,使用Java 8合规性编译它的事实取决于新的目标类型推断,它具有完全不同的规则。