Java 8默认方法是否会破坏源兼容性?

Pau*_*aul 54 java forward-compatibility java-8 default-method

通常情况下,Java源代码已向前兼容.在Java 8之前,据我所知,编译类源代码都已经与后来的JDK/JVM版本向前兼容.[更新:这是不正确的,请参阅下面的注释'en en'等.]但是,在Java 8中添加了默认方法后,似乎不再是这种情况.

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

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

所以我的基本问题是:

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

也:

  • 这是第一次这种前向不相容的变化吗?
  • 在设计和实施默认方法时是否考虑或讨论过这个问题?是否记录在任何地方?
  • 对于这些好处,(不可否认的是)不便打折吗?

以下是在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;
        }

    }

}
Run Code Online (Sandbox Code Playgroud)

以下显示了正在编译(或未能)并正在运行的代码.

> 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
Run Code Online (Sandbox Code Playgroud)

And*_*mas 57

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

超类或接口中的任何新方法都可能破坏兼容性.默认方法使接口中的更改不太可能破坏兼容性.从某种意义上说,默认方法打开了向接口添加方法的大门,你可以说默认方法可能会导致一些破坏的兼容性.

这是第一次这种前向不相容的变化吗?

几乎可以肯定的是,因为自从Java 1.0以来我们一直在从标准库中继承类.

在设计和实施默认方法时是否考虑或讨论过这个问题?是否记录在任何地方?

是的,有人考虑过了.请参阅Brian Goetz的2010年8月论文"Interface evolution via"公共辩护人"方法":

  1. 源兼容性

此方案可能会在修改库接口以插入与现有类中的方法不兼容的新方法的范围内引入源不兼容性.(例如,如果一个类有一个浮点值的xyz()方法并实现了Collection,并且我们将一个int值xyz()方法添加到Collection中,那么现有的类将不再编译.)

对于这些好处,(不可否认的是)不便打折吗?

之前,更改界面肯定会破坏兼容性.现在,它可能.从'绝对'到'可能'可以看到正面或负面.一方面,它可以向接口添加方法.另一方面,它打开了你所看到的那种不兼容性的大门,不仅仅是类,还有接口.

然而,正如Goetz论文顶部引用的那样,好处大于不便之处:

  1. 问题陈述

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

在JDK 7中为Java语言添加闭包会对老化的Collection接口造成额外的压力; 闭包最重要的好处之一是它可以开发更强大的库.添加一种语言功能可以实现更好的库,同时不扩展核心库以利用该功能,这将是令人失望的.

  • @Paul - 我同意,这是一种危险.但是,有一个中间路线.之前,谨慎的做法是永远不要改变公共界面.(例如,Bloch in*Effective Java*:"一旦界面发布并广泛实施,几乎不可能改变.")现在,我们可以喊出"这是红色时刻!" 并开始在公共接口中抛出默认方法.但我认为谨慎的方法是认识到我们已经从"破坏"变为"可能中断",并且当好处超过破坏某些实现的可能性时,小心地且不经常地添加默认方法. (3认同)
  • 具有讽刺意味的是,他们不得不抵制向Collection API添加许多有用的默认方法的诱惑,因为害怕破坏子类.更好的问题是为什么他们认为将`sort`添加到`List`是绝对必要的. (2认同)

dka*_*zel 9

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

是的,因为你已经看到了自己.

这是第一次这种前向不相容的变化吗?

没有.Java 5 enum关键字也在破坏,因为在此之前你可能有一些名为不能在Java 5 +中编译的变量

在设计和实施默认方法时是否考虑或讨论过这个问题?是否记录在任何地方?

Orcale Java 8源代码不兼容的描述

对于这些好处,(不可否认的是)不便打折吗?