How are Java generics different from C++ templates? Why can't I use int as a parameter?

JavaC++Generics

Java Problem Overview


I am trying to create

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

in Java but that does not work.

Can someone explain why int as type parameter does not work?
Using Integer class for int primitive works, but can someone explain why int is not accepted?

Java version 1.6

Java Solutions


Solution 1 - Java

Java generics are so different from C++ templates that I am not going to try to list the differences here. (See What are the differences between “generic” types in C++ and Java? for more details.)

In this particular case, the problem is that you cannot use primitives as generic type parameters (see JLS §4.5.1: "Type arguments may be either reference types or wildcards.").

However, due to autoboxing, you can do things like:

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

So that removes some of the pain. It definitely hurts runtime efficiency, though.

Solution 2 - Java

The reason that int doesn't work, is that you cannot use primitive types as generic parameters in Java.

As to your actual question, how C++ templates are different from Java generics, the answer is that they're really, really different. The languages essentially apply completely different approaches to implementing a similar end effect.

Java tends to focus on the definition of the generic. That is, the validity of the generic definition is checked by only considering the code in the generic. If parameters are not properly constrained, certain actions cannot be performed on them. The actual type it's eventually invoked with, is not considered.

C++ is the opposite. Only minimal verification is done on the template itself. It really only needs to be parsable to be considered valid. The actual correctness of the definition is done at the place in which the template is used.

Solution 3 - Java

They are very different concepts, which can be used to perform some, but not all of the same tasks. As said in the other responses, it would take a quite a bit to go over all the differences, but here's what I see as the broad strokes.

Generics allow for runtime polymorphic containers through a single instantiation of a generic container. In Java, all the (non-primitive) objects are references, and all references are the same size (and have some of the same interface), and so can be handled by the bytecode. However, a necessary implication of having only instantiation of byte code is type eraser; you can't tell which class the container was instantiated with. This wouldn't work in c++ because of a fundamentally different object model, where objects aren't always references.

Templates allow for compile time polymorphic containers through multiple instantiations (as well as template metaprogramming by providing a (currently weakly typed) language over the c++ type system.). This allows for specializations for given types, the downside being potential "code bloat" from needing more than one compiled instantiation.

Templates are more powerful than generics; the former is effectively another language embedded within c++, while to the best of my knowledge, the latter is useful only in containers

Solution 4 - Java

The main difference is in way they are implemented, but their names accurately describe their implementation.

Templates behave like templates. So, if you write:

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

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

Compiler applies the template, so in the end compiler treats the code like:

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

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

So, for each type which is used to call f a new code is "generated".

On the other hand, generics is only typechecked, but then all type information is erased. So, if you write:

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 compiles it like:

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();
...

In the end:

  • templates require instantiation of each call to templated function (in compilation of each .cpp file), so templates are slower to compile
  • with generics you can't use primitives, because they are not Object, so generics is less versatile

Solution 5 - Java

You can't use primitives as type parameters in Java. Java's generics worth through type erasure, meaning that the compiler checks that you're using the types as you've defined them, but upon compilation, everything is treated as an Object. Since int and other primitives aren't Objects, they can't be used. Instead, use Integer.

Solution 6 - Java

that's because int is a primitive, it is a known issue.

If you really wanted to, you can subclass/write your own collection that can do that.

Solution 7 - Java

You could try TIntArraList from GNU Trove which will act like an ArrayList of int values.

Solution 8 - Java

For your question, Java objects are somewhat equivalent to pointers in C++.

Java does garbage collection because those dynamic obejcts will be "unseen" (stop being pointed) at some point and then a space cleaning is needed.

int is recognized as a primitive type so that makes impossible to return null and that's the reason why Java generics cannot accept primitve types. To indicate that an element isn't stored inside a Java container as Map, Set, List, a method will return null. Then what are you going to return if you can't return null ?

For std::array, static and dynamic arrays, C++ forces you to define a default constructor, it's because as C++ arrays are arrays of types instead of arrays of pointers as in Java. You have to indicate which default value (null value in Java) is going to take the objects in such structure.

Think about it, in Java any object in an array is null by default, in C++ it isn't unleast you declare an array of pointers and set all those at 0x0 or (preferable) as nullptr.

Attributions

All content for this solution is sourced from the original question on Stackoverflow.

The content on this page is licensed under the Attribution-ShareAlike 4.0 International (CC BY-SA 4.0) license.

Content TypeOriginal AuthorOriginal Content on Stackoverflow
QuestionyesraajView Question on Stackoverflow
Solution 1 - JavaMichael MyersView Answer on Stackoverflow
Solution 2 - JavaJaredParView Answer on Stackoverflow
Solution 3 - JavaTodd GardnerView Answer on Stackoverflow
Solution 4 - JavakravemirView Answer on Stackoverflow
Solution 5 - JavaPestoView Answer on Stackoverflow
Solution 6 - Javaz -View Answer on Stackoverflow
Solution 7 - JavaPeter LawreyView Answer on Stackoverflow
Solution 8 - Javasɪʒɪhɪŋ βɪstɦa kxɐllView Answer on Stackoverflow