Почему дженерики Java не поддерживают примитивные типы?
Почему дженерики в Java работают с классами, но не с примитивными типами?
Например, это работает нормально:
List<Integer> foo = newArrayList<Integer>();
но это запрещено:
List<int> bar = newArrayList<int>();
Переведено автоматически
Ответ 1
Дженерики в Java являются полностью конструкцией времени компиляции - компилятор преобразует все универсальные варианты использования в приведение к нужному типу. Это делается для поддержания обратной совместимости с предыдущими средами выполнения JVM.
Это:
List<ClassA> list = newArrayList<ClassA>(); list.add(newClassA()); ClassAa= list.get(0);
Итак, все, что используется в качестве дженериков, должно быть конвертируемым в Object (в этом примере get(0) возвращает an Object), а примитивные типы - нет. Поэтому их нельзя использовать в дженериках.
Ответ 2
В Java дженерики работают так, как они работают ... по крайней мере частично ... потому что они были добавлены в язык через несколько лет после того, как язык был разработан1. Разработчики языка были ограничены в своих возможностях для дженериков из-за необходимости создавать дизайн, который был бы обратно совместим с существующим языком и библиотекой классов Java.
Другие языки программирования (например, C ++, C #, Ada) допускают использование примитивных типов в качестве типов параметров для дженериков. Но обратной стороной этого является то, что реализации дженериков (или шаблонных типов) в таких языках обычно влекут за собой генерацию отдельной копии универсального типа для каждой параметризации типа.
1 - Причина, по которой дженерики не были включены в Java 1.0, заключалась в нехватке времени. Они чувствовали, что им нужно быстро выпустить язык Java, чтобы использовать новые рыночные возможности, предоставляемые веб-браузерами. Джеймс Гослинг заявил, что он хотел бы включить дженерики, если бы у них было время. Как выглядел бы язык Java, если бы это произошло, можно только догадываться.
Ответ 3
В Java универсальные типы реализуются с помощью "стирания типов" для обратной совместимости. Все универсальные типы преобразуются в Object во время выполнения. например,
publicclassContainer<T> {
private T data;
public T getData() { return data; } }
будет рассматриваться во время выполнения как,
publicclassContainer {
private Object data;
public Object getData() { return data; } }
компилятор несет ответственность за обеспечение надлежащего приведения для обеспечения безопасности типов.
Container<Integer> val = newContainer<Integer>(); Integerdata= val.getData()
Текущая удаленная реализация Java, которая создает один класс для всех эталонных экземпляров и не поддерживает примитивные экземпляры. (Это однородный перевод, и ограничение, заключающееся в том, что дженерики Java могут работать только с ссылочными типами, исходит из ограничений однородного перевода в отношении набора байт-кодов JVM, который использует разные байт-коды для операций со ссылочными типами и примитивными типами.) Однако удаленные дженерики в Java обеспечивают как поведенческую параметричность (универсальные методы), так и параметричность данных (необработанные экземпляры универсальных типов и подстановочные знаки).)
...
была выбрана стратегия однородного преобразования, при которой переменные универсального типа стираются до их границ по мере их включения в байт-код. Это означает, что независимо от того, является класс универсальным или нет, он все равно компилируется в один класс с тем же именем и сигнатурами членов которого одинаковы. Безопасность типов проверяется во время компиляции, а среда выполнения не ограничена системой универсальных типов. В свою очередь, это наложило ограничение на то, что дженерики могут работать только со ссылочными типами, поскольку Object - это самый общий доступный тип, и он не распространяется на примитивные типы.