Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Instantiating generic type ArrayList<T>

Tags:

java

generics

I am new to generics and read in a article "A parameterized type, such as ArrayList<T>, is not instantiable — we cannot create instances of them".

Full quote, from Java in a Nutshell:

A parameterized type, such as ArrayList<T>, is not instantiable - we cannot create instances of them. This is because <T> is just a type parameter - merely a place-holder for a genuine type. It is only when we provide a concrete value for the type parameter, (e.g., ArrayList<String>), that the type becomes fully formed and we can create objects of that type.

This poses a problem if the type that we want to work with is unknown at compile time. Fortunately, the Java type system is able to accommodate this concept. It does so by having an explicit concept of the unknown type which is represented as <?>.

I understand that it should not be instantiable since the concrete (actual) type is not known. If so, why does the below code compiles without an error?

public class SampleTest {

    public static <T> List<T> getList(T... elements) {

        List<T> lst = new ArrayList<>(); // shouldn't this line return an error? 

        return lst;
    }
}

I know there is a gap in my understanding of generics here. Can someone point out what am i missing here?

like image 798
seeker27 Avatar asked Oct 02 '18 07:10

seeker27


People also ask

Can you instantiate a generic type?

Cannot Instantiate Generic Types with Primitive Types. Cannot Create Instances of Type Parameters. Cannot Declare Static Fields Whose Types are Type Parameters. Cannot Use Casts or instanceof With Parameterized Types.

What is the T in a ArrayList Java?

The type parameter in an instantiation expression of a parameterized type ( new ArrayList<T> ) is just used by the compiler to type-check the parameters passed to the constructor (there are none in this case) and to figure out the type returned by the expression; it is not used in any other way.


1 Answers

Because T is given as another generic type argument.

It's the whole purpose of generics to make the type parameterizeable. So the caller can specify the type. This can be done in multiple layers: the caller may also be generic and let its caller specify the type.

public static void main(String[] args)
{
  foo(7);
}

public static <T> void foo(T value)
{
  bar(value);
}

public static <U> void bar(U value)
{
  baz(value);
}

public static <V> void baz(V value)
{
  System.out.println(value.getClass().getSimpleName());
}

It prints out

Integer

A parameterized type, such as ArrayList<T>, is not instantiable

Means: You cannot create ArrayList of an unknown T. It must be specified at compile time. But it can be done indirectly, by another generic. In your case, it's another T, which will be specified again by the caller of your generic getList.


The wildcard <?> is something different. It is used to specify compatibility. <?> is the syntax to avoid specification of the type. You can use extends to require a basetype or interface. However, you cannot create instances with wildcards.

  List<?> list = new ArrayList<String>();
  list = new ArrayList<Integer>();

This wouldn't be possible otherwise. It makes most sense when using it in parameter specifications, for instance:

  public static int foo(List<? extends Comparable> list)
  {
     return list.get(1).compareTo(list.get(2));
  }

It's very confusing of this book. It assumes that <?> somehow solves the problem that a List with unknown T cannot be instantiated. IMHO, this is rubbish. T must be specified to create an instance.

like image 163
Stefan Steinegger Avatar answered Oct 26 '22 23:10

Stefan Steinegger