Подтвердить что ты не робот

Как отличительные черты Java отличаются от шаблонов С++? Почему я не могу использовать int в качестве параметра?

Я пытаюсь создать

ArrayList<int> myList = new ArrayList<int>();

в Java, но это не работает.

Может кто-нибудь объяснить, почему int как параметр типа не работает?
Использование класса Integer для примитивных работ int, но может ли кто-нибудь объяснить, почему int не принимается?

Java версия 1.6

4b9b3361

Ответ 1

Java-дженерики настолько отличаются от шаблонов С++, что я не собираюсь перечислять различия здесь. (См. Каковы различия между "родовыми" типами в С++ и Java? для более подробной информации.)

В данном конкретном случае проблема заключается в том, что вы не можете использовать примитивы в качестве параметров типового типа (см. JLS §4.5.1: "Тип аргументы могут быть либо ссылочными типами, либо подстановочными знаками." ).

Однако из-за автобоксинга вы можете делать такие вещи, как:

List<Integer> ints = new ArrayList<Integer>();
ints.add(3); // 3 is autoboxed into Integer.valueOf(3)

Таким образом, удаляется часть боли. Тем не менее, это определенно вредит эффективности работы.

Ответ 2

Причина, по которой int не работает, заключается в том, что вы не можете использовать примитивные типы в качестве общих параметров в Java.

Что касается вашего фактического вопроса, то как шаблоны С++ отличаются от дженериков Java, ответ на самом деле действительно отличается. Это по существу два совершенно разных подхода к реализации эффекта аналогичного.

Java, как правило, фокусируется на определении родового. Это справедливость общего определения проверяется только с учетом кода в родовом выражении. Если параметры не установлены должным образом, некоторые действия на них не могут выполняться. Фактический тип, с которым он в конечном итоге вызывается, не рассматривается.

С++ - это противоположность. Для самого шаблона выполняется только минимальная проверка. Это действительно нужно только быть понятным, чтобы считаться действительным. Фактическая правильность определения выполняется в том месте, где используется шаблон.

Ответ 3

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

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

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

Шаблоны более мощные, чем дженерики; первый - фактически другой язык, встроенный в С++, хотя, насколько мне известно, последний полезен только в контейнерах

Ответ 4

потому что int является примитивным, это известная проблема.

Если вы действительно этого захотите, вы можете подклассифицировать/написать свою собственную коллекцию, которая может это сделать.

Ответ 5

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

Ответ 6

Вы можете попробовать TIntArraList из GNU Trove, который будет действовать как ArrayList из значений int.

Ответ 7

Основное отличие в том, как они реализованы, но их имена точно описывают их реализацию.

Шаблоны ведут себя как шаблоны. Итак, если вы пишете:

template<typename T>
void f(T s)
{
    std::cout << s << '\n';
}

...
int x = 0;
f(x);
...

Компилятор применяет шаблон, поэтому в конце компилятор обрабатывает код вроде:

void f_generated_with_int(int s)
{
    std::cout << s << '\n';
}

...
int x = 0;
f_generated_with_int(x);
...

Итак, для каждого типа, который используется для вызова f, генерируется новый код.

С другой стороны, generics только typechecked, но тогда вся информация о типе стирается. Итак, если вы пишете:

class X<T> {
    private T x;

    public T getX() { return x; }
    public void setX(T x) { this.x = x; }
}

...
Foo foo = new Foo();
X<Foo> x = new X<>();
x.setX(foo);
foo = x.getX();
...

Java компилирует его так:

class X {
    private Object x;

    public Object getX() { return x; }
    public void setX(Object x) { this.x = x; }
}

...
Foo foo = new Foo();
X x = new X();
x.setX(foo);
foo = (Foo)x.getX();
...

В конце:

  • шаблоны требуют создания каждого вызова шаблонной функции (в компиляции каждого .cpp файла), поэтому шаблоны медленнее компилировать
  • с дженериками вы не можете использовать примитивы, потому что они не Object, поэтому обобщения менее универсальны.