这是简单的代码
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
当JAVA_HOME指向JDK 8并且我使用时,javac -source 1.7 SimpleTest.java
我得到
SimpleTest.java:9: error: incompatible types: ArrayList
当我使用-source 1.8
或不-source
选择任何选项时,一切正常。现在,当JAVA_HOME指向JDK 7时,无论是否使用,代码总是会编译-source 1.7
。
最初,这个问题是关于一个软件,其中POM文件具有与
设置1.7
和构建是失败的JDK 8,但也没关系的JDK 7。
现在要问的是-导致它发生的原因是什么?在我看来,这似乎是一种主要的忽视。为什么在source
设置为的JDK 8上编译1.7
失败?
您可以将代码简化为不需要第三方库的独立示例:
public class Test2 { @SafeVarargs staticArrayList newArrayList(T... arg) { return new ArrayList (Arrays.asList(arg)); } private final List > maps = newArrayList( createMap(null, Collections.EMPTY_MAP) ); public static Map createMap(String id, Map m) { return null; } }
这可以使用编译javac
从jdk1.7,但不能与javac
利用jdk1.8 -source 1.7
。
这里的要点是,javac
与以前版本中包含的jdk1.8相比,jdk1.8仍然是不同的编译器,并且该选项-source 1.7
不会告诉它模仿旧实现的行为,而是与Java 7 规范兼容。如果旧的编译器有错误,则新的编译器不必尝试重现该错误。
由于代码使用Collections.EMPTY_MAP
而不是Collections.
,原始类型Map
将传递给createMap
,从而使其成为具有原始结果类型的未经检查的调用Map
。
这是JLS§15.12.2.6要求的:
所选方法的结果类型确定如下:
如果以返回类型为void声明所选方法,则结果为void。
否则,如果要使该方法适用就必须进行未经检查的转换,则结果类型是该方法的声明的返回类型的擦除(第4.6节)。
…
似乎尚未在javac
jdk1.7中完全实现此行为。有趣的是,添加类型参数时,它将正确执行此操作
public staticMap createMap(String id, Map m)
使其成为通用方法。然后,jdk1.7将产生相同的错误。但是引用的规则适用于所有方法调用。
相反,使用Java 8兼容性进行编译成功的事实源于具有完全不同规则的新目标类型推断。