Java 8 缺省方法会破坏源代码兼容性吗?

通常情况下,Java源代码是向前兼容的。据我所知,在Java 8之前,编译的类源代码都与后来的JDK / JVM版本向前兼容。[更新:这是不正确的,请参阅下面的注释“枚举”等。但是,随着 Java 8 中添加默认方法,情况似乎不再如此。

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

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

所以我的基本问题是:

  • 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:\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

答案 1

JDK 1.8 不是因为默认方法而为 Java 源代码引入了前向不兼容吗?

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

这是第一个这样的向前不兼容的更改吗?

几乎可以肯定不是,因为我们从Java 1.0开始就从标准库中对类进行了子类化。

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

是的,它被考虑了。参见Brian Goetz在2010年8月的论文“通过”公设辩护人“方法进行界面进化”

  1. 源兼容性

此方案可能会引入源不兼容,以至于修改库接口以插入与现有类中的方法不兼容的新方法。(例如,如果一个类具有浮点值 xyz() 方法并实现了 Collection,并且我们将一个整数值 xyz() 方法添加到 Collection,则现有类将不再编译。

(诚然很小的)不便是否与福利相比打了折扣?

以前,更改接口肯定会破坏兼容性。现在,它可能会。从“绝对”到“可能”可以正面或负面地看待。一方面,它使向接口添加方法成为可能。另一方面,它打开了你所看到的那种不兼容的大门,不仅与类,而且在接口上。

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

  1. 问题陈述

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

在JDK 7中向Java语言添加闭包给老化的集合接口带来了额外的压力;闭包最重要的好处之一是,它支持开发更强大的库。如果添加一个语言功能,该功能可以实现更好的库,同时又不扩展核心库以利用该功能,那将是令人失望的。


答案 2

JDK 1.8 不是因为默认方法而为 Java 源代码引入了前向不兼容吗?

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

这是第一个这样的向前不兼容的更改吗?

不。Java 5关键字也正在中断,因为在此之前,您可以将变量命名为不再在Java 5 +中编译的变量。enum

在设计和实现默认方法时,是否考虑或讨论过这一点?它是否记录在任何地方?

是的,Orcale Java 8 源代码不兼容说明

(诚然很小的)不便是否与福利相比打了折扣?

是的


推荐