Почему версия Java 1.5 требует обратной совместимости? - PullRequest
0 голосов
/ 07 июня 2019

Java 1.5 была выпущена с Generics, и они хотели, чтобы она была обратно совместима с более ранними версиями, и, следовательно, Java запретила использование специфических для метода обобщений при создании необработанных экземпляров.

например,

class A<T> {
    <U> U myMethod(U u) {
        return u;
    }
}

Если я это сделаю,

A a = new A();

a.myMethod попросит меня передать Object в качестве входных данных, и его типом возврата будет Object. Ясно, что параметр типа класса 'T' не конфликтует с определенным универсальным выражением myMethod (), которое является "U". Но как-то сказал Java, чтобы справиться с обратной совместимостью, они стирают использование всех обобщений для необработанных экземпляров.

Приведенный выше вопрос задают несколько раз другие, и все ответы вращаются, говоря, из-за обратной совместимости с более ранними версиями Java это запрещено. [ДОТ].

Но ни один из ответов не предоставил экземпляр того, что могло произойти с ошибкой в ​​более ранних версиях в случае, если java разрешил использование специфических для метода обобщений для необработанных экземпляров.

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

Пожалуйста, не предоставляйте никаких других вопросов о стековом потоке, на которые нет ответа, относящихся к тому, что могло не получиться.

Ответы [ 2 ]

5 голосов
/ 07 июня 2019

Рассмотрим программу на Java, которая была написана для использования типов коллекций Java до Java 1.5.

До Java 1.5 я писал бы

 List l = new ArrayList();
 l.append("Hello");
 l.append("World");
 String hello = (String) l.get(0);

Теперь, используя модель стирания типов, я могу скомпилировать этот код в Java 1.5 или более поздней версии ... даже без предупреждения компилятора. Но я также могу использовать точно такие же классы коллекций современным способом; например,

 List<String> l = new ArrayList<>();
 l.append("Hello");
 l.append("World");
 String hello = l.get(0);

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

Без модели стирания для разметки трещин разработчикам Java пришлось бы создавать параллельный набор классов и интерфейсов для коллекций; т.е.

  • Коллекции до 1.5 без обобщений и параметров типа
  • Коллекции Post-1.5 с обобщениями и параметрами типов

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

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


Мы не можем дать вам конкретные примеры, которые доказуемо не будут работать на языке Java, где обобщенные элементы основаны на шаблонах и / или не были удалены.

  • Этот гипотетический язык Java не существует.
  • При условии достаточных усилий разработчика любая Java-программа до 1.5 могла бы быть перенесена на такой язык.
2 голосов
/ 07 июня 2019

При добавлении обобщений к языку Java команда Java хотела удовлетворить следующие требования (среди прочих):

  • Код, скомпилированный для Java 4, и код, скомпилированный для Java 5, должны быть в состоянии сосуществоватьв одной и той же JVM и беспрепятственно взаимодействуют
  • Код библиотеки, написанный для Java 4, должен иметь возможность переноситься на Java 5 таким образом, чтобы не нарушать бинарную совместимость

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

Основная трудность возникла из-за модернизации инфраструктуры сбора Java API сгенерики таким образом, чтобы не нарушать существующий код.Например, рассмотрим библиотеку Java 4, которая объявляет:

public List getFactories();

и используется в существующем приложении Java 4, которое:

List list = getFactories();

Теперь предположим, что приложение обновлено до Java 5до библиотеки.Какой тип параметра они указывают?Они могут сказать:

  • List factories = getFactories();

    ... но это лишает новый код возможности использовать дженерики

  • List<Object> factories = getFactories()

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

  • List<Factory> factories = getFactories();

    ..... но это не будет безопасным типом: так как во время создания не был указан параметр типа при создании объекта List, он не может проверить, что List содержит только фабрики (или принудительно установить, что это так и есть).устаревший код продолжает взаимодействовать с List)

  • List<Factory> factories = new ArrayList<Factory>(getFactories);

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

Команда Java выбрала вариант 3 и частично смягчила воздействие, потребовав, чтобы компилятор предупреждал об отсутствии безопасности типов, и попросив компилятор вставлять синтетические приведения для проверки типа каждого отдельного объекта всписок перед использованием, тем самым сохраняя целостность системы типов времени выполнения при небольшом снижении производительности (и значительных затратах здравомыслия разработчика при сбое такого приведения).

Интересно отметить, что команда разработчиков C #, столкнувшаяся по существу с тем же затруднением при введении обобщений в C # и CLR несколькими годами ранее, решила нарушить обратную совместимость, чтобы преобразовать универсальные типы.Как следствие, им пришлось ввести совершенно новую платформу для сбора (а не просто модифицировать существующую платформу для сбора, как это сделала Java).

Оглядываясь назад, я думаю, что команда .NET здесь сделала лучший выбор, потому что это позволило им развивать язык, а не увековечивать его ограничения.По крайней мере, обоснование их проектных решений не нуждается в объяснении спустя десятилетие: -)

...