Java 8默认方法是否打破源代码兼容性?
通常情况下,Java源代码已向前兼容。 据我所知,在Java 8之前,编译的类和源都与后来的JDK / JVM版本向前兼容。 [更新:这是不正确的,见下面的评论重新'枚举',等等。]但是,随着在Java 8中添加默认方法,这似乎不再是这种情况。
例如,我一直使用的库有java.util.List
的实现,它包含List<V> sort()
。 此方法返回已排序列表内容的副本。 该库作为jar文件依赖项进行部署,在使用JDK 1.8构建的项目中运行良好。
然而,后来我有机会使用JDK 1.8重新编译库本身,我发现库不再编译:带有自己的sort()
方法的List
实现类现在与Java 8 java.util.List.sort()
默认方法。 Java 8 sort()
默认方法对列表进行排序(返回void
); 我的库的sort()
方法 - 因为它返回一个新的排序列表 - 具有不兼容的签名。
所以我的基本问题是:
也:
以下是一些在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:toolsjdk1.7.0_10binjavac Sort8.java
> c:toolsjdk1.7.0_10binjava Sort8 this is a test
unsorted: [this, is, a, test]
sorted : [this, test, is, a]
> c:toolsjdk1.8.0_05binjava Sort8 this is a test
unsorted: [this, is, a, test]
sorted : [this, test, is, a]
> del Sort8*.class
> c:toolsjdk1.8.0_05binjavac 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添加了一个int值的xyz()方法,则现有类将不再编译。)
这个(不可否认的)小小的不便折扣了吗?
之前,更改界面肯定会破坏兼容性。 现在,它可能。 从“绝对”到“可能”从正面或负面看都可以看出来。 一方面,它可以为接口添加方法。 另一方面,它为您所看到的那种不兼容性打开了大门,不仅仅是类,而且还有接口。
然而,正如Goetz的论文中所指出的那样,这些好处大于不便之处:
一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法。 图书馆出版后的时间越长,这种限制就越有可能导致维护者的悲痛。
在JDK 7中增加对Java语言的闭包给老化的Collection接口增加了额外的压力; 闭包的最大好处之一是它可以开发更强大的库。 如果添加一个语言功能,可以创建更好的库,同时不扩展核心库以利用该功能,那将是令人失望的。
由于缺省方法,JDK 1.8是否为Java源代码引入了前向不兼容?
是的,因为你已经看到你的自我。
这是第一次这种前瞻性不兼容的变化吗?
不,Java 5 enum
关键字也是因为在这之前,你可能拥有那些不再能在Java 5 +中编译的变量
当设计和实施的默认方法是否被考虑或讨论过? 它记录在任何地方吗?
是Orcale Java 8源不兼容性描述
这个(不可否认的)小小的不便折扣了吗?
是
我们可以绘制一个抽象类的平行线。 一个抽象类是打算被子类化的,以便可以实现抽象方法。 抽象类本身包含调用抽象方法的具体方法。 抽象类可以通过添加更具体的方法来自由演变; 这种做法可能会破坏子类。
因此,甚至在Java8之前,你所描述的确切问题就存在了 这个问题在Collection API上表现得更加突出,因为在野外有很多子类。
尽管默认方法的主要动机是在不破坏子类的情况下为现有的Collection API添加一些有用的方法,但由于害怕破坏子类,它们必须对此做太多的自我控制。 只有在绝对必要时才会添加默认方法。 这里真正的问题是,为什么List.sort
被认为是绝对必要的。 我认为这是有争议的。
无论首先引入默认方法,它现在对于API设计者来说都是一个很好的工具,我们应该把它和抽象类中的具体方法一样对待 - 它们需要事先仔细设计; 并且必须非常小心地引入新的。
链接地址: http://www.djcxy.com/p/73655.html