Java 8默认方法是否打破源代码兼容性?

一般情况下,Java源代码已经向前兼容。 据我所知,在Java 8之前,编译后的类源代码都与后来的JDK / JVM版本兼容。 [更新:这是不正确的,见下面的评论重新'枚举'等]。但是,随着在Java 8中添加默认方法,这似乎不再是这种情况。

例如,我一直使用的库有java.util.List的实现,它包含一个List<V> sort() 。 此方法返回已sorting列表内容的副本。 这个部署为jar文件依赖项的库在使用JDK 1.8构build的项目中运行良好。

然而,后来我有机会使用JDK 1.8重新编译库本身,我发现库不再编译:带有自己的sort()方法的List实现类现在与Java 8 java.util.List.sort()默认方法。 Java 8 sort()默认方法对列表进行sorting(返回void ); 我的库的sort()方法 – 因为它返回一个新的sorting列表 – 具有不兼容的签名。

所以我的基本问题是:

  • 由于默认方法,JDK 1.8是否为Java源代码引入了前向不兼容?

也:

  • 这是第一次这样的前锋不兼容的变化吗?
  • 当devise和实施的默认方法是否被考虑或讨论过? 它logging在任何地方吗?
  • 这个(确实很小)的不便是折扣而不是好处?

以下是一些在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以来,我们已经从标准库中inheritance了类。

是否在devise和实施默认方法时考虑或讨论过? 它logging在任何地方吗?

是的,这是考虑。 请参阅Brian Goetz 2010年8月的论文“通过公共辩护者”方法“进行界面进化 :

  1. 源代码兼容性

这种scheme可能会引入源不兼容性,以至于库接口被修改为插入与现有类中的方法不兼容的新方法。 (例如,如果一个类有一个浮点值的xyz()方法并实现了Collection,并且我们向Collection添加一个int值的xyz()方法,则现有的类将不再编译。

这个(确实很小)的不便是折扣而不是好处?

之前,更改界面肯定会破坏兼容性。 现在,它可能 。 从“绝对”到“可能”从正面或负面看。 一方面可以为接口添加方法。 另一方面,它为您所看到的那种不兼容性敞开了大门,不仅仅是类,而且还有接口。

然而,正如戈茨的论文所指出的那样,这些好处比不便之处还要大:

  1. 问题陈述

一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法。 图书馆出版的时间越长,这个限制就越有可能给维护者带来悲痛。

在JDK 7中增加对Java语言的闭包给老化的Collection接口增加了额外的压力; closures的最大好处之一是它能够开发更强大的图书馆。 添加一个语言特性,使得更好的库,同时不扩展核心库,以利用该function将是令人失望的。

由于默认方法,JDK 1.8是否为Java源代码引入了前向不兼容?

是的,因为你已经看到你的自我。

这是第一次这样的前锋不兼容的变化吗?

不,Java 5的enum关键字也被打破了,因为在这之前你可以拥有那些不再能在Java 5 +中编译的variables

当devise和实施的默认方法是否被考虑或讨论过? 它logging在任何地方吗?

是Orcale Java 8源不兼容性描述

这个(确实很小)的不便是折扣而不是好处?

我们可以与抽象类相提并论。 一个抽象类是打算被分类的,以便抽象方法可以被实现。 抽象类本身包含调用抽象方法的具体方法。 抽象类可以通过增加更具体的方法来自由进化; 而这种做法可能会打破子类。

因此,甚至在Java8之前,您所描述的确切问题就存在 这个问题在Collection API上performance得更加突出,因为这里有很多的子类。

尽pipe默认方法的主要动机是在不破坏子类的情况下为现有的Collection API添加一些有用的方法,但由于害怕破坏子类,他们必须对此做太多的自我控制。 只有在绝对必要时才会添加默认方法。 这里真正的问题是,为什么List.sort被认为是绝对必要的。 我认为这是有争议的。

不pipe为什么默认方法是首先引入的,它现在是APIdevise者的一个很好的工具,我们应该把它和抽象类中的具体方法一样对待 – 它们需要事先仔细devise; 而且必须非常小心地引入新的。

讽刺的是,接口中默认的方法被引入,以允许使用这些接口的现有库中断,同时在接口中引入大量的function。 (向后兼容)

像这样的sort方法可能会出现冲突。 支付额外function的东西。 在你的情况也是一些调查(应该使用新的function呢?)。

Java向前兼容性的突破很小,更多的是在其打字系统,这是不断扩大。 首先使用genericstypes,然后使用函数接口的推断types。 从版本到版本,从编译器到编译器都有细微的差别。

读这个问题,我想到了它的解决scheme。
默认方法已经解决了向后兼容性问题,但是向前兼容性问题将会存在
我认为,而不是扩展现有的类,在这种情况下,我们可以让我们的应用程序特定的接口添加一些所需的行为,我们的类。 我们可以实现这个应用程序特定的接口并使用它。