2015-10-14 3 views
5

Вопрос из книги:Java 8 - по умолчанию методы - проблемы для унаследованного кода

В прошлом (до Java 8), вы сказали, что это плохая форма, чтобы добавить методы к интерфейсу, потому что это сломает существующий код. Теперь вам говорят, что добавлять новые методы легко, если вы также предоставляете реализацию по умолчанию.

  1. Насколько это безопасно? Опишите сценарий, в котором новый метод stream интерфейса Collection приводит к сбою компиляции устаревшего кода.
  2. Что касается бинарной совместимости? Будет ли унаследованного кода из файла JAR-прежнему работать?»

Мои ответы таковы, но я не совсем уверен, что о них.

  1. Это безопасно, только если унаследованный код не обеспечивает метод с таким же именем stream и с той же подписью (например, в унаследованном классе, который реализует Collection). В противном случае этот старый устаревший код не скомпилирует.
  2. Я думаю, что двоичная совместимость сохранена, старый код из старого JAR-файла все равно будет работать Но у меня нет никаких явных доводов в отношении s.

Может ли кто-либо подтвердить или отклонить эти ответы или добавить еще несколько аргументов, ссылок или ясности в эти ответы?

+0

[Соответствующий] (http://stackoverflow.com/a/22618640/335858). – dasblinkenlight

+1

Выполнение этой задачи при сохранении бинарной совместимости было основной мотивацией добавления методов по умолчанию к языку.Добавление стандартного к существующему методу является двоичным и совместимым с исходным кодом; добавление нового метода со значением по умолчанию является двоичным и совместимым с исходным кодом (по модулю взаимодействия с методами конфлирования в подклассах - это имеет идентичные характеристики совместимости с добавлением нового метода в класс, не являющийся конечным.) –

+1

Хотя бинарная совместимость сохраняется, возникают проблемы, когда он взаимодействует с поведением библиотеки JRE, как в [этом сценарии] (http://stackoverflow.com/q/26816650/2711488). Вы также можете считать, что метод может иметь * совместимую * подпись, таким образом, начинает переопределять новый метод 'default', не намереваясь его ... – Holger

ответ

8
  1. Новый метод stream() по умолчанию в Collection возвращает Stream<E>, а также новый тип в Java 8. унаследованный код не сможет компиляции, если он содержит stream() метод с той же сигнатурой, но возвращение что-то другое, в результате чего столкновение типов возврата.

  2. Код устаревшего кода будет продолжать работать до тех пор, пока он не будет перекомпилирован.

Во-первых, в 1.7, установить следующее:

public interface MyCollection { 
    public void foo(); 
} 

public class Legacy implements MyCollection { 
    @Override 
    public void foo() { 
     System.out.println("foo"); 
    } 

    public void stream() { 
     System.out.println("Legacy"); 
    } 
} 

public class Main { 
    public static void main(String args[]) { 
     Legacy l = new Legacy(); 
     l.foo(); 
     l.stream(); 
    } 
} 

С -source 1.7 -target 1.7, это компилируется и работает:

$ javac -target 1.7 -source 1.7 Legacy.java MyCollection.java Main.java 
$ java Main 
foo 
Legacy 

Теперь в 1.8, мы добавим метод потока в MyCollection ,

public interface MyCollection 
{ 
    public void foo(); 
    public default Stream<String> stream() { 
     return null; 
    } 
} 

Скомпилировать только MyCollection в 1.8.

$ javac MyCollection.java 
$ java Main 
foo 
Legacy 

Конечно, мы не можем перекомпилировать Legacy.java больше.

$ javac Legacy.java 
Legacy.java:11: error: stream() in Legacy cannot implement stream() in MyCollection 
    public void stream() 
       ^
    return type void is not compatible with Stream<String> 
1 error 
+5

Обратите внимание, что этот угловой код совместимости не является новым по умолчанию; эта же проблема присутствовала в Java 1.0, если вы добавили метод к суперклассу, который несовместим с однотипным методом в каком-то подклассе. Добавление методов к интерфейсам с настройками по умолчанию имеет те же самые характеристики совместимости, что и методы добавления классов. –

+3

Я думаю, что методы столкновения - это меньшая проблема, поскольку компилятор их видит. Большая проблема возникает, когда подпись не сталкивается. С 'stream()', это невозможно, поскольку возвращаемый тип является новым классом. Но подумайте о 'sort (Comparator)'. Такой метод можно использовать в пользовательской реализации «List» до Java 8, и до Java 8 реализация этого метода путем делегирования «Collections.sort» была бы разумной. Теперь 'Collections.sort' делегирует' List.sort', который метод pre-Java 8 переопределяет без намерения. Компилятор не расскажет вам об этой проблеме ... – Holger

Смежные вопросы