Тип стирания - это больше, чем просто функция байтового кода, которую вы можете включить или выключить.
Это влияет на работу всей среды выполнения. Если вы хотите иметь возможность запрашивать общий тип каждого экземпляра универсального класса, это означает, что метаинформация, сопоставимая с представлением среды выполнения Class
, создается для каждого экземпляра объекта универсального класса.
Если вы пишете new ArrayList<String>(); new ArrayList<Number>(); new ArrayList<Object>()
вы не только создаете три объекта, вы потенциально создает три дополнительных мета-объектов, отражающих типы, ArrayList<String>
, ArrayList<Number>
и ArrayList<Object>
, если они не существовали до этого.
Учтите, что в типовом приложении используются тысячи разных подписей List
, большинство из которых никогда не использовались в месте, где требуется наличие такого отражения (из-за отсутствия этой функции мы могли бы заключить, что в настоящее время , все они работают без такого отражения).
Это, разумеется, умножается на тысячи разных типов списков типов, подразумевающих тысячи разных типов итераторов, тысяч разделителей и потоковых воплощений, даже не считая внутренних классов реализации.
И это даже влияет на места без выделения объекта, которые в настоящее время исследуют стирание типа под капотом, например. Collections.emptyList()
, Function.identity()
или Comparator.naturalOrder()
и т. Д. Возвращают один и тот же экземпляр при каждом вызове. Если вы настаиваете на том, чтобы учитываемый particalar тип общего типа отражался, он больше не работает. Так что, если вы пишете
List<String> list=Collections.emptyList();
List<Number> list=Collections.emptyList();
вы должны получить два различных экземпляры, каждый из них отчеты разного по getClass()
или будущему эквиваленту.
Кажется, люди, желающие этой способности имеют узкий взгляд на их конкретный метод, в котором было бы здорово, если бы они могли рефлекторно выяснить, является ли один конкретный параметр на самом деле один из двух или трех типов, но никогда не думайте о весе передачи метаинформации о потенциально сотни или тысячи генерирующих экземпляров тысяч родовых классов.
Это то место, где мы должны спросить, что мы получаем взамен: способность поддерживать сомнительный стиль кодирования (это то, что влияет на поведение кода из-за информации, найденной через Reflection).
Ответ до сих пор только рассмотрел легкий аспект удаления типа стирания, то желание вникать тип фактического экземпляра. Фактический экземпляр имеет конкретный тип, о котором можно сообщить. Как упоминалось в this comment от user the8472, требование удаления стирания типа часто также подразумевает желание быть отличным до (T)
или создать массив через new T[]
или получить доступ к типу переменной типа через T.class
.
Это поднимет истинный кошмар. Переменная типа - это другой зверь, чем фактический тип конкретного экземпляра. Переменная типа может быть разрешена, например, ? extends Comparator<? super Number>
, чтобы назвать один (довольно простой) пример. Предоставление необходимой метаинформации подразумевает, что не только распределение объектов становится намного дороже, каждый вызов метода может налагать эти дополнительные затраты еще шире, так как теперь мы не только говорим о комбинации родовых классов с фактическими классами, но и также всевозможные подстановочные комбинации, даже вложенные родовые типы.
Имейте в виду, что фактический тип параметра типа также может ссылаться на другие параметры типа, превращая проверку типов в очень сложный процесс, который вам необходимо не только повторять для каждого типа приведения, если вы позволяете создавать массив из него, каждая операция хранения должна повторить его.
Помимо большой проблемы с производительностью, сложность вызывает еще одну проблему. Если вы посмотрите список отслеживания ошибок javac
или связанные с ним вопросы Stackoverflow, вы можете заметить, что этот процесс не только сложный, но и подверженный ошибкам. В настоящее время каждая младшая версия javac
содержит изменения и исправления в отношении соответствия подписи общего типа, влияющие на то, что будет принято или отклонено. Я уверен, вам не нужны внутренние операции JVM, такие как приведение типов, назначения переменных или массивы массивов, чтобы стать жертвой этой сложности, имея другое представление о том, что является законным или нет в каждой версии, или внезапно отвергает то, что javac
приняло на время компиляции из-за правил несоответствия.
Обратная совместимость никогда не терялась. Старая программа Java 1.1, скорее всего, по-прежнему будет работать гладко на JRE 8 VM, о чем говорят связанные сообщения. – Tunaki
@ Тунаки исправьте меня, если я ошибаюсь, но это передовая совместимость: ваш код будет работать на будущих JVM. Если мы удалим стирание типа в JVM версии X, оно все равно будет удалено в JVM X + 1, поэтому наш код все равно будет работать. – Prime
Не совсем, см. Также http://stackoverflow.com/questions/4692626/is-jdk-upward-or-backward-compatible – Tunaki