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

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

Например, это прекрасно работает:

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

но это не разрешено:

List<int> bar = new ArrayList<int>();

Ответ 1

Generics в 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);

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

Ответ 2

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

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


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

Ответ 3

В коллекциях задан тип, который имеет значение java.lang.Object. Базисы просто этого не делают.

Ответ 4

В java generics реализованы с помощью "Стирание типа" для обратной совместимости. Все общие типы преобразуются в 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", поэтому мы не можем использовать его как общий тип.

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

Ответ 5

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

Предполагается, что он появится на Java 10 под Project Valhalla.

В Брайан Гетц документ Состояние специализации

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

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

...

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