关于java 8向后兼容性的问题:JDK中的新方法

And*_*niy 5 java backwards-compatibility java-8

简单的问题.在Java 8中,我们在JDK类中有大量新方法.假设我们使用Java 7(或Java 6)创建了这样的类:

class MyArrayList<E> extends ArrayList<E> {
        public void sort(Comparator<E> c) {
            // some sort
        }
}
Run Code Online (Sandbox Code Playgroud)

这是非常合理的实施.现在我们尝试使用Java 8编译它并收到可预期的编译错误:

error: name clash: sort(Comparator<E#1>) in MyArrayList and sort(Comparator<? super E#2>) in ArrayList have the same erasure, yet neither overrides the other
            public void sort(Comparator<E> c) {
                        ^   where E#1,E#2 are type-variables:
    E#1 extends Object declared in class I.MyArrayList
    E#2 extends Object declared in class ArrayList
Run Code Online (Sandbox Code Playgroud)

在这里,我想提出2个问题:

  1. 即使javac -source 1.7 -target 1.7使用JDK 8选项,我也收到同样的错误 - 为什么?我认为这些选项应该允许编译遗留代码.

  2. 一般的向后兼容性怎么样?

编辑准确地说,可能是我做错了什么?JDK 1.8.0_65,Mac OS X:

bash-3.2$ javac -version
javac 1.8.0_65
bash-3.2$ javac -source 1.7 -target 1.7 MyArrayList.java 
warning: [options] bootstrap class path not set in conjunction with -source 1.7
MyArrayList.java:7: error: name clash: sort(Comparator<E#1>) in MyArrayList and sort(Comparator<? super E#2>) in ArrayList have the same erasure, yet neither overrides the other
    public void sort(Comparator<E> c) {
                ^
  where E#1,E#2 are type-variables:
    E#1 extends Object declared in class MyArrayList
    E#2 extends Object declared in class ArrayList
1 error
1 warning
Run Code Online (Sandbox Code Playgroud)

JB *_*zet 7

  1. 因为即使使用这些选项,您仍然在编译Java 8类.JDK不知道在哪个版本的JDK中出现了哪些方法.所有这些选项都告诉编译器只接受您正在编译的代码中的Java 7语法,并生成Java 7字节码.您必须将实际链接传递给JDK 7类(使用该-bootclasspath选项)进行交叉编译.

  2. 是的,这是一个问题.并不是很大,并且拥有所有这些新的默认方法的好处比使用一些罕见的非编译代码的不便更重要.

  • 这就是我默认做的事情.除非我有一个可以与Java 7一起使用的库/框架,但是当与Java 8一起使用时提供了附加值,或者必须支持仅存在于Java 8中的类.以Spring为例:它本身支持java中的类.时间包,但与Java 7兼容. (2认同)

Viv*_*ath 7

  1. -source 1.7只说源使用Java 7语言功能.-target 1.7表示输出的字节码针对特定版本的JVM.但是,您仍在编译JDK 8.由于您是交叉编译的,因此您必须告诉javac使用-bootclasspath和存在Java 7的引导程序和扩展类的位置-extdirs
  2. 接口中的默认方法(在Java 8中引入)允许您在不破坏现有代码的情况下添加新功能.它不是一个防弹解决方案,可能会有一些小问题(这个答案会详细解释这些问题).但总的来说,兼容性问题非常罕见.

  • 不必要.这样,您可以只维护运行时库jar和所需的任何其他扩展,而不是维护特定版本的*whole*JDK分发.此外,您可以使用一个编译器编译到不同的目标,而不必在您需要的目标的编译器版本之间切换(使工具更容易).但是,如果您已经拥有JDK 7,那么您并不严格*需要*使用JDK 8来编译JDK 7代码.这取决于你的用例. (2认同)