简体   繁体   English

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

[英]Do Java 8 default methods break source compatibility?

It has generally been the case the Java source code has been forward compatible. 通常情况下,Java源代码已向前兼容。 Until Java 8, as far as I know, both compiled classes and source have been forward compatible with later JDK/JVM releases. 在Java 8之前,据我所知,编译类源代码都已经与以后的JDK / JVM版本向前兼容。 [Update: this is not correct, see comments re 'enum', etc, below.] However, with the addition of default methods in Java 8 this appears to no longer be the case. [更新:这是不正确的,请参阅下面的注释'en en'等。]但是,在Java 8中添加了默认方法后,似乎不再是这种情况。

For example, a library I have been using has an implementation of java.util.List which includes a List<V> sort() . 例如,我一直使用的库有一个java.util.List的实现,它包含一个List<V> sort() This method returns a copy of the contents of the list sorted. 此方法返回已排序的列表内容的副本。 This library, deployed as a jar file dependency, worked fine in a project being built using JDK 1.8. 这个库作为jar文件依赖项部署,在使用JDK 1.8构建的项目中运行良好。

However, later I had occasion to recompile the library itself using JDK 1.8 and I found the library no longer compiles: the List -implementing class with its own sort() method now conflicts with the Java 8 java.util.List.sort() default method. 但是,后来我有机会使用JDK 1.8重新编译库本身,我发现库不再编译: List -implementing类及其自己的sort()方法现在与Java 8 java.util.List.sort()冲突默认方法。 The Java 8 sort() default method sorts the list in place (returns void ); Java 8 sort()默认方法对列表进行排序(返回void ); my library's sort() method - since it returns a new sorted list - has an incompatible signature. 我的库的sort()方法 - 因为它返回一个新的排序列表 - 具有不兼容的签名。

So my basic question is: 所以我的基本问题是:

  • Doesn't JDK 1.8 introduce a forward incompatibility for Java source code due to default methods? 由于默认方法,JDK 1.8是否为Java源代码引入了前向不兼容性?

Also: 也:

  • Is this the first such forward incompatible change? 这是第一次这种前向不相容的变化吗?
  • Was this considered or discussed when default methods where designed and implemented? 在设计和实施默认方法时是否考虑或讨论过这个问题? Is it documented anywhere? 是否记录在任何地方?
  • Was the (admittedly small) inconvenience discounted versus the benefits? 对于这些好处,(不可否认的是)不便打折吗?

The following is an example of some code that compiles and runs under 1.7 and runs under 1.8 - but does not compile under 1.8: 以下是在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;
        }

    }

}

The following shows this code being compiled (or failing to) and being run. 以下显示了正在编译(或未能)并正在运行的代码。

> 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

Doesn't JDK 1.8 introduce a forward incompatibility for Java source code due to default methods? 由于默认方法,JDK 1.8是否为Java源代码引入了前向不兼容性?

Any new method in a superclass or interface can break compatibility. 超类或接口中的任何新方法都可能破坏兼容性。 Default methods make it less likely that a change in an interface will break compatibility. 默认方法使接口中的更改不太可能破坏兼容性。 In the sense that default methods open the door to adding methods to interfaces, you could say that default methods may contribute to some broken compatibility. 从某种意义上说,默认方法打开了向接口添加方法的大门,你可以说默认方法可能会导致一些破坏的兼容性。

Is this the first such forward incompatible change? 这是第一次这种前向不相容的变化吗?

Almost certainly not, since we've been subclassing classes from the standard library since Java 1.0. 几乎可以肯定的是,因为自从Java 1.0以来我们一直在从标准库中继承类。

Was this considered or discussed when default methods were designed and implemented? 在设计和实施默认方法时是否考虑或讨论过这个问题? Is it documented anywhere? 是否记录在任何地方?

Yes, it was considered. 是的,有人考虑过了。 See Brian Goetz's August 2010 paper "Interface evolution via “public defender” methods" : 请参阅Brian Goetz的2010年8月论文“Interface evolution via”公共辩护人“方法”

  1. Source compatibility 源兼容性

It is possible that this scheme could introduce source incompatibilities to the extent that library interfaces are modified to insert new methods that are incompatible with methods in existing classes. 此方案可能会在修改库接口以插入与现有类中的方法不兼容的新方法的范围内引入源不兼容性。 (For example, if a class has a float-valued xyz() method and implements Collection, and we add an int-valued xyz() method to Collection, the existing class will no longer compile.) (例如,如果一个类有一个浮点值的xyz()方法并实现了Collection,并且我们将一个int值xyz()方法添加到Collection中,那么现有的类将不再编译。)

Was the (admittedly small) inconvenience discounted versus the benefits? 对于这些好处,(不可否认的是)不便打折吗?

Before, changing an interface would definitely break compatibility. 之前,更改界面肯定会破坏兼容性。 Now, it might . 现在,它可能 Going from 'definitely' to 'might' can be seen either positively or negatively. 从'绝对'到'可能'可以看到正面或负面。 On the one hand, it makes it feasible to add methods to interfaces. 一方面,它可以向接口添加方法。 On the other hand, it opens the door to the kind of incompatibility you saw, not just with classes, but with interfaces too. 另一方面,它打开了你所看到的那种不兼容性的大门,不仅仅是类,还有接口。

The benefits are larger than the inconveniences, though, as cited at the top of Goetz's paper: 然而,正如Goetz论文顶部引用的那样,好处大于不便之处:

  1. Problem statement 问题陈述

Once published, it is impossible to add methods to an interface without breaking existing implementations. 一旦发布,就不可能在不破坏现有实现的情况下向接口添加方法。 The longer the time since a library has been published, the more likely it is that this restriction will cause grief for its maintainers. 自图书馆发布以来的时间越长,这种限制就越有可能给其维护者带来悲痛。

The addition of closures to the Java language in JDK 7 place additional stress on the aging Collection interfaces; 在JDK 7中为Java语言添加闭包会对老化的Collection接口造成额外的压力; one of the most significant benefits of closures is that it enables the development of more powerful libraries. 闭包最重要的好处之一是它可以开发更强大的库。 It would be disappointing to add a language feature that enables better libraries while at the same time not extending the core libraries to take advantage of that feature. 添加一种语言功能可以实现更好的库,同时不扩展核心库以利用该功能,这将是令人失望的。

Doesn't JDK 1.8 introduce a forward incompatibility for Java source code due to default methods? 由于默认方法,JDK 1.8是否为Java源代码引入了前向不兼容性?

Yes as you've seen your self. 是的,因为你已经看到了自己。

Is this the first such forward incompatible change? 这是第一次这种前向不相容的变化吗?

No. Java 5 enum keyword was also breaking because before that you could have variables named that which would no longer compile in Java 5 + 没有.Java 5 enum关键字也破坏了,因为在此之前你可以拥有名为不再在Java 5 +中编译的变量

Was this considered or discussed when default methods where designed and implemented? 在设计和实施默认方法时是否考虑或讨论过这个问题? Is it documented anywhere? 是否记录在任何地方?

Yes Orcale Java 8 source incompatibility description Orcale Java 8源代码不兼容的描述

Was the (admittedly small) inconvenience discounted versus the benefits? 对于这些好处,(不可否认的是)不便打折吗?

Yes

We can draw a parallel with abstract class. 我们可以与抽象类绘制并行。 An abstract class is intended to be subclassed so that the abstract methods can be implemented. 抽象类旨在被子类化,以便可以实现抽象方法。 The abstract class itself contains concrete methods that invoke the abstract methods. 抽象类本身包含调用抽象方法的具体方法。 The abstract class is free to evolve by adding more concrete methods; 抽象类可以通过添加更具体的方法自由发展; and this practice may break subclasses. 而这种做法可能会破坏子类。

Therefore the exact problem you described existed even before Java8. 因此,您所描述的确切问题甚至在Java8之前就存在了。 The problem is much more manifested on Collection APIs because there are a lot of subclasses out in the wild. 问题更多地体现在Collection API上,因为野外有很多子类。

While the leading motivation of default method was to add some useful methods to existing Collection APIs without breaking subclasses, they had to exercise great self-control of doing it too much, for fear of breaking subclasses. 虽然默认方法的主要动机是在不破坏子类的情况下向现有Collection API添加一些有用的方法,但是由于害怕破坏子类,因此必须对其进行过多的自我控制。 A default method is added only if it's absolutely necessary. 只有在绝对必要的情况下才会添加默认方法。 The real question here is, why List.sort is considered absolutely necessary. 这里真正的问题是,为什么List.sort被认为是绝对必要的。 I think that is debatable. 我认为这是值得商榷的。

Regardless of why default method was introduced in the 1st place, it is now a great tool for API designers, and we ought to treat it the same as concrete methods in abstract classes - they need to be designed carefully up front; 无论为什么默认方法被引入第一位,它现在是API设计者的一个很好的工具,我们应该像抽象类中的具体方法一样对待它们 - 它们需要在前面仔细设计; and new ones must be introduced with great caution. 必须非常谨慎地介绍新的。

Ironically default methods in interfaces were introduced to allow existing libraries using those interfaces not to break, while introducing massive new functionality in the interfaces. 具体而言,引入了接口中的默认方法,以允许使用这些接口的现有库不会中断,同时在接口中引入大量功能。 (backward compatibility.) (向后兼容。)

Conflicts like that sort method might arise. 可能会出现类似sort方法的冲突。 Something to pay for the extra functionality. 支付额外功能的东西。 In your case also something to investigate (should new functionality be used instead?). 在你的情况下也需要调查(应该使用新功能吗?)。

Java forward compatibility breaks are little, more in its typing system, which was constantly enlarged. Java前向兼容性中断很少,更多的是它的打字系统,它不断扩大。 First with generic types and now with inferred types from functional interfaces. 首先是泛型类型,现在是功能接口的推断类型。 From version to version and from compiler to compiler there were slight differences. 从版本到版本以及从编译器到编译器都存在细微差别。

Reading this issue, I was thinking of its solution. 阅读这个问题,我在想它的解决方案。
Default methods have solved the backward compatibility problems but forward compatibility issues will exist. 默认方法已解决了向后兼容性问题,但存在前向兼容性问题。
I think instead of extending existing classes, in such cases, we can have our application specific interfaces to add some desired behaviour to our class. 我认为,在这种情况下,我们可以使用特定于应用程序的接口来向我们的类添加一些所需的行为,而不是扩展现有的类。 We can implement this application specific interface and use it. 我们可以实现这个特定于应用程序的接口并使用它

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM