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()方法 - 因为它返回一个新的排序列表 - 具有不兼容的签名。

所以我的基本问题是:

  • 由于缺省方法,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;
            }
    
        }
    
    }
    

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

    > 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

    上一篇: Do Java 8 default methods break source compatibility?

    下一篇: Is a Java string really immutable?