Основное отличие состоит в том, как они реализованы, но их имена точно описывают их реализацию.
Шаблоны ведут себя как шаблоны. Итак, если вы напишите:
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
, генерируется новый код.
С другой стороны, дженерики проверяются только по типам, но затем вся информация о типах стирается. Итак, если вы напишите:
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
, поэтому дженерики менее универсальны