Смешивание Java 1.4 и 1.6 байт-кода в иерархии классов

Вопрос в первую очередь, история будет следовать:

Безопасно ли смешивать разные версии байт-кода в иерархии классов? Каковы риски?

Для случая, класс C расширяет B, класс B расширяет класс A. Класс A реализует интерфейс I. Мой вопрос может включать следующие примеры сценариев:

  • Класс A скомпилирован в байт-код Java 1.6 и имеет функции 1.6, такие как обобщенные и т. Д. Наследники, которые являются B и C, были скомпилированы в байт-код 1.4.
  • Интерфейс я скомпилировал до 1.6, а разработчик скомпилировал до 1.4.
  • Другой экзотический сценарий наследования с использованием другой версии байт-кода.

Я перепробовал столько сценариев, сколько мог представить, и, кажется, все работает отлично. Однако я все еще чувствую желание спросить здесь, поскольку я знаю только Java на поверхности; я знаю, как кодировать и настраивать Java, но на самом деле не знаю, что происходит под капотом.

Теперь для тех умов, которые не могут помочь себе спросить: "Зачем тебе это делать???".

Я нахожусь в проекте по оценке миграции старого приложения Java 1.4 Swing, подключенного к EJB 2 через RMI, на Java 1.6 Swing, подключенного к более новой версии сервера приложений, работающей поверх версии 1.6. Платформа J2EE все еще будет 1.4 (EJB 2).

Миграция не будет "перекомпилировать все до 1.6", но будет "кодировать и компилировать новые функции до 1.6". То, как они делают вещи, выглядит следующим образом: у них только один путь в CVS, каждый принимает его. Никаких тегов / веток, чтобы получить производственный код. Всякий раз, когда необходимо добавить новую функцию, они получают JAR-файлы с рабочего сервера, взрывают их, заменяют или добавляют новые классы по мере необходимости, перепаковывают файлы JAR, возвращают их на сервер. Поэтому, если они будут использовать Java 6 для компиляции и использовать вышеуказанный метод для развертывания, будет много экзотических миксов из 1,4 и 1,6 байт-кодов.

5 ответов

Решение

Байт-код JVM существенно не отличается между Java 1.0 и Java 6. В Java 7 они добавляют одну новую инструкцию. Woohoo.

Есть так мало изменений в том, как работает байт-код, что

  • JVM не поддерживает вложенные классы, обращающиеся к закрытым членам внешних классов, это работает через сгенерированный код.
  • JVM не поддерживает проверки времени выполнения для дженериков, например, вы не можете new T() где T является общим.

По сути, они делают JVM умнее и быстрее, но до недавнего времени любой ценой избегали изменения модели работы байт-кода.

Вы можете скомпилировать с Java 6, но цель 1.4 с настройкой компилятора. Мы сделали это для проекта миграции один раз. Если / когда 1.4 исчезнет, ​​вы снова измените настройки компилятора и нацелитесь на 1.6.

Сохранение целевой версии в явном виде также означает, что вы можете обновить SDK, не опасаясь, что ваши JAR-файлы станут непригодными для использования с более старой JVM.

Я поддерживаю среду с классами 1.4 (старые библиотеки jar) и 1.5 (мои исправления и прочее) на Tomcat, используя Sun JVM 1.5, и она работает нормально.

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

Лучший способ выяснить это - сделать концептуальный тип проекта небольшим.

Дружеское напоминание, тем не менее, вы вырыли довольно большую дыру для себя здесь:-)

Пока вы не используете отражение, единственная серьезная проблема, которая может возникнуть при использовании разных версий байт-кода, - это ACC_SUPER флаг.

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

Однако это древняя история. Каждый класс, скомпилированный в 1.4 и позже, будет иметь флаг, так что это не проблема. С точки зрения байт-кода, единственное существенное различие между 1.4 и 1.6 заключается в добавлении дополнительных атрибутов, используемых для хранения метаданных о внутренних классах, обобщениях, аннотациях и т. Д.

Однако они напрямую не влияют на выполнение байт-кода. Единственный способ, которым они оказывают влияние, - это если вы получаете к ним доступ через отражение. Например, java.lang.Class.getDeclaredClasses() вернет информацию из необязательного атрибута InnerClasses,

Эти ссылки кажутся актуальными. Они документируют несколько крайних случаев, которые могут нарушить совместимость между 1,4 и 1,5 и между 1,5 и 1,6.

Самые большие различия, которые могут вызвать проблемы, о которых я могу подумать, это то, что enum стал ключевым словом, но это повлияет только на 1.5+ JVM при загрузке файла более старого класса (что, похоже, не то, что вы будете делать). Другое дело, аннотации. Похоже, что приведенные выше ссылки говорят о том, что все будет хорошо, но я бы с осторожностью отнесся к тому, что произойдет, если старая JVM загрузит класс с аннотациями времени выполнения.

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

Другие вопросы по тегам