Вопрос-ответ

Why don't Java Generics support primitive types?

Почему дженерики Java не поддерживают примитивные типы?

Почему дженерики в Java работают с классами, но не с примитивными типами?

Например, это работает нормально:

List<Integer> foo = new ArrayList<Integer>();

но это запрещено:

List<int> bar = new ArrayList<int>();
Переведено автоматически
Ответ 1

Дженерики в Java являются полностью конструкцией времени компиляции - компилятор преобразует все универсальные варианты использования в приведение к нужному типу. Это делается для поддержания обратной совместимости с предыдущими средами выполнения JVM.

Это:

List<ClassA> list = new ArrayList<ClassA>();
list.add(new ClassA());
ClassA a = list.get(0);

превращается в (примерно):

List list = new ArrayList();
list.add(new ClassA());
ClassA a = (ClassA)list.get(0);

Итак, все, что используется в качестве дженериков, должно быть конвертируемым в Object (в этом примере get(0) возвращает an Object), а примитивные типы - нет. Поэтому их нельзя использовать в дженериках.

Ответ 2

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

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


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

Ответ 3

В Java универсальные типы реализуются с помощью "стирания типов" для обратной совместимости. Все универсальные типы преобразуются в Object во время выполнения. например,

public class Container<T> {

private T data;

public T getData() {
return data;
}
}

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

public class Container {

private Object data;

public Object getData() {
return data;
}
}

компилятор несет ответственность за обеспечение надлежащего приведения для обеспечения безопасности типов.

Container<Integer> val = new Container<Integer>();
Integer data = val.getData()

станет

Container val = new Container();
Integer data = (Integer) val.getData()

Теперь вопрос в том, почему "Object" выбирается в качестве типа во время выполнения?


Ответ таков: Object является суперклассом всех объектов и может представлять любой пользовательский объект.


Поскольку все примитивы не наследуются от "Object", мы не можем использовать его как универсальный тип.


К вашему сведению: Project Valhalla пытается решить вышеуказанную проблему.

Ответ 4

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

Предполагается, что это появится в Java 10 в рамках проекта Valhalla.

В статье Брайана Гетца о состоянии специализации

Существует отличное объяснение причины, по которой дженерики не поддерживались для primitive. И, как это будет реализовано в будущих выпусках Java.


Текущая удаленная реализация Java, которая создает один класс для всех эталонных экземпляров и не поддерживает примитивные экземпляры. (Это однородный перевод, и ограничение, заключающееся в том, что дженерики Java могут работать только с ссылочными типами, исходит из ограничений однородного перевода в отношении набора байт-кодов JVM, который использует разные байт-коды для операций со ссылочными типами и примитивными типами.) Однако удаленные дженерики в Java обеспечивают как поведенческую параметричность (универсальные методы), так и параметричность данных (необработанные экземпляры универсальных типов и подстановочные знаки).)


...


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


java generics