Java源代码通常是向前兼容的。据我所知,在Java 8之前,编译类 和 源代码都已与更高版本的JDK / JVM版本向前兼容。[更新:这是不正确的,请参见下面有关“枚举”的注释,等等。]但是,在Java 8中添加了默认方法后,情况似乎不再如此。
例如,我一直在使用的库的实现java.util.List包括一个List<V> sort()。此方法返回已排序列表内容的副本。该库以jar文件依赖项的形式部署,在使用JDK 1.8构建的项目中运行良好。
java.util.List
List<V> sort()
但是,后来我有机会使用JDK 1.8重新编译该库本身,但发现该库不再编译:List-implementing类及其自己的sort()方法现在与Java 8 java.util.List.sort()默认方法冲突。Java 8的sort()默认方法对列表进行适当排序(返回void)。我的图书馆的sort()方法(由于它返回了一个新的排序列表)具有不兼容的签名。
List
sort()
java.util.List.sort()
void
所以我的基本问题是:
也:
以下是一些代码的示例,这些代码可在1.7下编译并运行,而在1.8下运行-但不能在1.8下编译:
import java.util.*; public final class Sort8 { public static void main(String[] args) { SortableList<String> l = new SortableList<String>(Arrays.asList(args)); System.out.println("unsorted: "+l); SortableList<String> s = l.sort(Collections.reverseOrder()); System.out.println("sorted : "+s); } public static class SortableList<V> extends ArrayList<V> { public SortableList() { super(); } public SortableList(Collection<? extends V> col) { super(col); } public SortableList<V> sort(Comparator<? super V> cmp) { SortableList<V> l = new SortableList<V>(); l.addAll(this); Collections.sort(l, cmp); return l; } } }
下面显示了正在编译(或失败)并正在运行的代码。
> c:\tools\jdk1.7.0_10\bin\javac Sort8.java > c:\tools\jdk1.7.0_10\bin\java Sort8 this is a test unsorted: [this, is, a, test] sorted : [this, test, is, a] > c:\tools\jdk1.8.0_05\bin\java Sort8 this is a test unsorted: [this, is, a, test] sorted : [this, test, is, a] > del Sort8*.class > c:\tools\jdk1.8.0_05\bin\javac Sort8.java Sort8.java:46: error: sort(Comparator<? super V>) in SortableList cannot implement sort(Comparator<? super E>) in List public SortableList<V> sort(Comparator<? super V> cmp) { ^ return type SortableList<V> is not compatible with void where V,E are type-variables: V extends Object declared in class SortableList E extends Object declared in interface List 1 error
由于默认方法,JDK 1.8不会为Java源代码引入向前的不兼容性吗?
超类或接口中的任何新方法都可能破坏兼容性。默认方法使接口更改破坏兼容性的 可能性降低 。从默认方法打开向接口添加方法的角度来看,您可以说默认方法可能会导致某些破坏性的兼容性。
这是第一个这样的向前不兼容的变化吗?
几乎可以肯定不是,因为自Java 1.0以来,我们一直在从标准库中继承类。
在设计和实现默认方法时是否考虑或讨论了此问题? 它记录在任何地方吗?
是的,有人考虑过。请参阅Brian Goetz在2010年8月发表的论文“通过“公共防御者”方法进行接口演变”:
源兼容性 如果修改库接口以插入与现有类中的方法不兼容的新方法,则该方案可能会引入源不兼容性。(例如,如果一个类具有浮点值的xyz()方法并实现Collection,并且我们向Collection添加一个整数值的xyz()方法,则现有的类将不再编译。)
如果修改库接口以插入与现有类中的方法不兼容的新方法,则该方案可能会引入源不兼容性。(例如,如果一个类具有浮点值的xyz()方法并实现Collection,并且我们向Collection添加一个整数值的xyz()方法,则现有的类将不再编译。)
(公认的很小的)不便与收益相抵触了吗?
以前,更改接口 肯定会 破坏兼容性。现在,它 可能会 。从“肯定”到“可能”的转变可以被正面或负面地看待。一方面,使向接口添加方法成为可能。另一方面,它打开了您所看到的那种不兼容的大门,不仅与类有关,而且与接口也有关。
但是,正如Goetz论文顶部所引述的,好处大于不便之处:
问题陈述 一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法。自从库发布以来,时间越长,此限制对其维护者造成痛苦的可能性就越大。 JDK 7中对Java语言的闭包的添加给老化的Collection接口带来了更多压力。闭包最显着的好处之一是,它使开发更强大的库成为可能。添加一种语言功能以启用更好的库同时不扩展核心库以利用该功能将是令人失望的。
一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法。自从库发布以来,时间越长,此限制对其维护者造成痛苦的可能性就越大。
JDK 7中对Java语言的闭包的添加给老化的Collection接口带来了更多压力。闭包最显着的好处之一是,它使开发更强大的库成为可能。添加一种语言功能以启用更好的库同时不扩展核心库以利用该功能将是令人失望的。