Generics are erased at runtime
Java generics exist only at compile time for type checking; the compiler erases them to raw types (and
inserts casts) in the bytecode. List<String> and List<Integer> are literally the same class object at
runtime, and there is no way to ask a List<T> what T is. A direct consequence: you cannot new T[n]
inside a generic class — the compiler can't erase that to anything meaningful.
import java.util.*;
List<String> ls = new ArrayList<>();
List<Integer> li = new ArrayList<>();
System.out.println("List<String> and List<Integer> share a runtime class: " + (ls.getClass() == li.getClass()));
System.out.println("runtime class: " + ls.getClass());
System.out.println("`ls instanceof List<String>` even compiles down to a raw `instanceof List` check --");
System.out.println("the type argument gives no runtime discrimination at all: " + (ls instanceof List<String>));
And here's the actual compiler error you get if you try to create a generic array directly (captured from a real javac run, not paraphrased):
// Reproduced verbatim from `javac` on:
// class GenArr<T> { T[] makeArray(int n) { return new T[n]; } }
//
// GenArr.java:4: error: generic array creation
// return new T[n];
// ^
// 1 error
System.out.println("(see markdown/comment above -- this is a compile-time error, can't be caught at runtime)");