2013-02-20 3 views
25

Я читал Effective Java от Joshua Bloch.Что такое бинарная совместимость в Java?

В пункте 17: «Используйте интерфейсы только для определения типов», я наткнулся на объяснение, где не рекомендуется использовать интерфейсы для хранения констант. Я объясню ниже.

«Хуже того, она представляет собой обязательство: если в будущем выпуске класс модифицирован таким образом, что она больше не нужно использовать константы, он все еще должен реализовать интерфейс для обеспечения бинарной совместимости .»

Что здесь означает бинарная совместимость?

Может ли кто-нибудь привести меня с примером на Java, чтобы показать, что код совместим с двоичным кодом.

+0

Http: // docs.oracle.com/javase/specs/jls/se7/html/jls-13.html –

+0

Незаменимая ссылка при рассмотрении изменений, потенциально нарушающих двоичную совместимость: https: //wiki.eclipse.org/Evolving_Java-based_APIs_2 – jordanpg

ответ

24

Короче говоря, двоичная совместимость означает, что при смене класса вам не нужно перекомпилировать классы, которые его используют. Например, вы удалили или переименовали в общественном месте или защищенный метод из этого класса

public class Logger implements Constants { 
    public Logger getLogger(String name) { 
     return LogManager.getLogger(name); 
    } 
} 

из журнала-1.jar библиотеки и выпустили новую версию как лог-2.jar. Когда пользователи вашего log-1.jar загружают новую версию, она сломает свои приложения, когда они попытаются использовать отсутствующий метод getLogger (String name).

И если вы удалите интерфейс Constants (пункт 17), это приведет к потере бинарной совместимости по той же причине.

Но вы можете удалить/переименовать частный или пакетный частный член этого класса, не нарушая бинарную совместимость, поскольку внешние приложения не могут (или не должны) использовать его.

+0

Меня поражает то, что официальная документация не может объяснить свои вещи с такой степенью простоты. Я не уверен, почему они хотят использовать аналогичных юристов, которые обычно используют в терминах и соглашениях. – Tarik

+2

У Ричарда Литтла есть очень простой, приятный пример на его [блоге] (http://codefhtagn.blogspot.kr/2010/11/java-binary-compatibility-more-than.html). Это действительно ** показывает проблему двоичной совместимости, а не совместимость с исходным кодом, как показано в этом ответе (с переименованным методом). –

-1

Для того, чтобы все выглядело просто:

Компьютер, который может работать один и тот же двоичный код, предназначенный для запуска на другом компьютере, называется двоично-совместимыми. Это отличается от совместимости с исходным кодом, где может потребоваться перекомпиляция.

Бинарная совместимость является основным преимуществом при разработке компьютерных программ, которые должны запускаться на нескольких операционных системах.

+0

Я верю, что вы говорите, это не тот же аспект, что и OP, спрашивая –

+0

Вопрос о бинарной совместимости в Java. Вы только что скопировали и ввели часть определения Википедии «бинарная совместимость». – sversch

6

Двоичная совместимость

Java бинарная совместимость предусматривает условия, при которых modication и повторное составление классов делает не требует повторной компиляции дополнительных классов импортны т modied классов. Двоичная совместимость - это концепция для языкового дизайна.

Java language specication [7] описывает бинарные ком- изменения совместимы следующим образом:

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

13

Чтобы лучше понять концепцию, интересно видеть, что двоичная совместимость НЕ подразумевает совместимость API, а также наоборот.

API совместимо, но двоично не совместимы: статическое удаление

Version 1 из библиотеки: Код

public class Lib { 
    public static final int i = 1; 
} 

Клиента:

public class Main { 
    public static void main(String[] args) { 
     if ((new Lib()).i != 1) throw null; 
    } 
} 

компилировать код клиента с версией 1:

javac Main.java 

Заменить версию 1 с версией 2: удалить static:

public class Lib { 
    public final int i = 1; 
} 

Рекомпилированные только версия 2, не код клиента, и запустить java Main:

javac Lib.java 
java Main 

Мы получаем:

Exception in thread "main" java.lang.IncompatibleClassChangeError: Expected static field Lib.i 
     at Main.main(Main.java:3) 

Это происходит потому что хотя мы можем написать (new Lib()).i в Java как для static, так и для методов членов, он компилируется в две разные команды VM в зависимости от Lib: getstatic или getfield. Этот разрыв упоминаются в JLS 7 13.4.10:

Если поле, которое не объявлено приватный не было объявлено статическими и изменено быть объявлено статическим, или наоборот, то ошибка связи, в частности, IncompatibleClassChangeError, приведет ли поле используется уже существующим двоичным кодом, которое ожидает поле другого типа.

Нам нужно перекомпилировать Main с javac Main.java для того, чтобы работать с новой версией.

Примечания:

  • призывают статические члены из экземпляров класса, как (new Lib()).i плохой стиль, поднимает предупреждение, и никогда не должно быть сделано
  • этот пример надуманный, так как не статические final примитивы бесполезны: всегда использование static final для примитивов: private final static attribute vs private final attribute
  • отражающий можно использовать to see the difference. Но отражение также может видеть частные поля, что, очевидно, приводит к разрыву, который не должен считаться перерывами, поэтому он не учитывается.

Binary совместимы, но НЕ API совместимы: нуль условием укрепления

Версия 1:

public class Lib { 
    /** o can be null */ 
    public static void method(Object o) { 
     if (o != null) o.hashCode(); 
    } 
} 

Версия 2:

public class Lib { 
    /** o cannot be null */ 
    public static void method(Object o) { 
     o.hashCode(); 
    } 
} 

Клиент:

public class Main { 
    public static void main(String[] args) { 
     Lib.method(null); 
    } 
} 

На этот раз, даже если перекомпилировать Main после обновления Lib, второй вызов будет брошен, но не первый.

Это потому, что мы сменили договор method таким образом, который нельзя проверить во время компиляции Java: прежде чем он сможет принять null, после этого больше нет.

Примечание:

  • вика Затмение является отличным источником для этого: https://wiki.eclipse.org/Evolving_Java-based_APIs
  • делает API, которые принимают null значения является сомнительной практикой
  • это гораздо легче сделать изменения, нарушающее API совместимость, но не двоичная, чем наоборот, так как легко изменить внутреннюю логику методов
+0

IMHO первый пример неверен, потому что вы удаляете 'static', и теперь это несовместимость API (то есть,' Lib.i' в байт-коде не работает больше). Разумная совместимость API для некоторого кода не зависит от того, используют ли клиенты этот API, но стандарт (или спецификацию) для совместимости с API. Хотя я согласен, что совместимость с API не подразумевает совместимость с двоичными файлами. – floating

0

Если в будущем мы хотим изменить e интерфейс, реализуемый некоторыми классами (например, добавление некоторых новых методов).

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

Чтобы преодолеть это, мы можем добавить по умолчанию методов в интерфейсе.

Это приведет к удалению зависимости для реализации дополнительных методов.

Нам не нужно модифицировать класс внедрения для внесения изменений. Это называется бинарной совместимостью.

См пример ниже:

интерфейс, который мы будем использовать

//Interface  
    interface SampleInterface 
      { 
       // abstract method 
       public void abstractMethod(int side); 

       // default method 
       default void defaultMethod() { 
        System.out.println("Default Method Block"); 
       } 

       // static method 
       static void staticMethod() { 
        System.out.println("Static Method Block"); 
       } 
      } 


//The Class that implements the above interface. 

    class SampleClass implements SampleInterface 
    { 
     /* implementation of abstractMethod abstract method, if not implemented 
     will throw compiler error. */ 
     public void abstractMethod(int side) 
     {System.out.println(side*side);} 

     public static void main(String args[]) 
     { 
      SampleClass sc = new SampleClass(); 
      sc.abstractMethod(4); 

      // default method executed 
      sc.defaultMethod(); 

      // Static method executed 
      SampleInterface.staticMethod(); 

     } 
    } 

Примечание: Для получения более подробной информации, пожалуйста, обратитесь default methods

+0

Стандартные и статические методы доступны в Java версии 8 или более. –

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