Методы Java 8 по умолчанию нарушают совместимость с исходным кодом?
как правило, исходный код Java был совместим с прямой передачей. До Java 8, насколько я знаю, оба скомпилированные классы и источник был вперед совместим с более поздними выпусками JDK/JVM. [Обновление: это неверно, см. комментарии re 'enum' и т. д. Ниже. Однако, с добавлением методов по умолчанию в 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); метод-так как он возвращает новый отсортированный список - имеет несовместимую подпись.
Итак, мой основной вопрос:
- разве 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
5 ответов:
разве JDK 1.8 не вводит прямую несовместимость для исходного кода Java из-за методов по умолчанию?
любой новый метод в суперклассе или интерфейсе может нарушить совместимость. Методы по умолчанию делают это меньше вероятность что изменение в интерфейсе нарушит совместимость. В том смысле, что методы по умолчанию открывают дверь для добавления методов в интерфейсы, можно сказать, что методы по умолчанию могут способствовать некоторым нарушениям совместимость.
Это первое такое прямое несовместимое изменение?
почти наверняка нет, так как мы были подклассы классов из стандартной библиотеки с Java 1.0.
это рассматривалось или обсуждалось при разработке и реализации методов по умолчанию? Это где-нибудь задокументировано?
Да, это было учтено. См. статью Брайана Гетца от августа 2010 года интерфейс" эволюция с помощью методов "народного защитника":
- совместимость с источниками
возможно, что эта схема может привести к несовместимости источников в той мере, в какой библиотечные интерфейсы изменяются для вставки новых методов, несовместимых с методами в существующих классах. (Например, если класс имеет поплавок стоимостью АБВ() метод и сбор инвентаря, и добавить интервал значениями XYZ (с) метод сбора, существующего класса больше не будет компилироваться.)
был (правда, небольшой) дискомфорт, скидки и льготы?
раньше изменение интерфейса было бы наверняка нарушить совместимость. Теперь это может. Переход от "определенно" к "могло бы" можно увидеть либо положительно, либо отрицательно. С одной стороны, это позволяет добавлять методы к интерфейсам. С другой стороны, это открывает дверь к виду несовместимость вы видели, не только с классами, но и с интерфейсами тоже.
преимущества больше, чем неудобства, хотя, как указано в верхней части статьи Гетца:
сообщении
после публикации невозможно добавить методы в интерфейс, не нарушая существующие реализации. Чем больше времени прошло с момента публикации библиотеки, тем больше вероятность того, что это ограничение вызовет горе для его сопровождающих.
добавление замыканий к языку Java в JDK 7 создает дополнительную нагрузку на устаревающие интерфейсы коллекций; одним из наиболее значительных преимуществ замыканий является то, что он позволяет разрабатывать более мощные библиотеки. Было бы неутешительно добавить языковую функцию, которая позволяет улучшить библиотеки, в то же время не расширяя основные библиотеки, чтобы воспользоваться этой функцией.
разве JDK 1.8 не вводит прямую несовместимость для исходного кода Java из-за методов по умолчанию?
да как вы видели себя.
Это первое такое прямое несовместимое изменение?
нет. Java 5
enumключевое слово также ломалось, потому что до этого у вас могли быть переменные с именем, которые больше не будут компилироваться в Java 5 +была этого рассматривать и обсуждать, когда по умолчанию методы где разработаны и реализованы? Это где-нибудь задокументировано?
да Orcale Java 8 Описание несовместимости источника
был (правда, небольшой) дискомфорт, скидки и льготы?
да
можно провести параллель с абстрактным классом. Абстрактный класс предназначен для подклассов, так что абстрактные методы могут быть реализованы. Сам абстрактный класс содержит конкретные методы, которые вызывают абстрактные методы. Абстрактный класс может свободно развиваться, добавляя более конкретные методы; и эта практика может разбить подклассы.
поэтому точная проблема, которую вы описали, существовала еще до Java8. Проблема гораздо больше проявляется в API-интерфейсах коллекций, потому что есть много подклассов в дикой природе.
в то время как основной мотивацией метода по умолчанию было добавление некоторых полезных методов к существующим API-интерфейсам коллекции без нарушения подклассов, они должны были проявлять большой самоконтроль, делая это слишком много, опасаясь нарушения подклассов. Метод по умолчанию добавляется только если это абсолютно необходимо. Реальный вопрос здесь, почему
List.sortявляется абсолютно необходимым. Я думаю, что это спорно.независимо от того, почему метод по умолчанию был представлен в 1 - м месте, теперь это отличный инструмент для дизайнеров API, и мы должны относиться к нему так же, как к конкретным методам в абстрактных классах-их нужно тщательно разрабатывать заранее; и новые должны быть введены с большой осторожностью.
по иронии судьбы методы по умолчанию в интерфейсах были введены, чтобы позволить существующим библиотекам использовать эти интерфейсы не сломать, вводя массивный новая функции в интерфейсах. (обратная совместимость.)
конфликты, как
sortспособ может возникнуть. Что-то платить за дополнительную функциональность. В вашем случае также что-то исследовать (следует ли вместо этого использовать новую функциональность?).совместимость Java вперед перерывов немного, больше в его системе набора текста, которая постоянно расширялась. Сначала с универсальными типами, а теперь с выводимыми типами из функциональных интерфейсов. От версии к версии и от компилятора к компилятору были небольшие различия.
читая этот вопрос, я думал о его решении.
методы по умолчанию решили проблемы обратной совместимости, но проблемы прямой совместимости будут существовать.
Я думаю, что вместо расширения существующих классов, в таких случаях, мы можем иметь наши приложения конкретных интерфейсов, чтобы добавить некоторые желаемое поведение в наш класс. Мы можем реализовать этот интерфейс приложения и использовать его.
Comments