Back to the main page

Generics
Generics allow template style classes. A class or method can be defined with a type placeholder. The placeholder is replaced with an actual type when the class or method is used.

The JVM knows nothing of generics, type information is stripped out during compilation. The generics type information is used during an earlier stage of compilation to provide type safety.

class MyClassName<C> {
   C myVariable;
   List<C> myList;

   C myMethod(C c) {
      myVariable = c;
      return myVariable;
   }

   static <M extends Number & Comparable<M>>int myMethod(M m) {
      ...
   }

   <M>void setObject(M m) {
      ...
   }
}

   List<Number> myNumberList = new ArrayList<Number>();

   // From Java SE 8 onwards we can reduce to ...
   List<Double> myDoubleList = new ArrayList<>();

   MyClassName<Number> myNumber = new MyClassName<Number>();

   // Type inferred from the parameter
   myNumber.setMyNumber(new Number(1));

   // NB Double maybe a subclass of Number but
   // List<Double> is not a subclass of List<Number>

Static methods and variables cannot use class level defined types because of type erasure. MyClassName<Integer> and MyClassName<Double> compile down to the same bytecode.

Collections can use wildcards <?> which allows any class to be used in place of the placeholder. Wildcards can be restricted by either extends or super.
List<? extends Number> is best used for reading or deleting from a list - you can't add a Number to a List<Double>.
List<? super Number> can be safely used for adding to the list, assuming you're adding a Number.

Subclassing generic classes...

class MySubClass extends MyClassGenericClass<Integer> {
   void setData(Integer i) {...}
}

Because of type erasure this no longer overrides void setData(T t) so the compiler will insert an overriding method.

   void setData(Object o) {
      this.setData((Integer)o);
   }


Non-reifiable types are those that have had type information removed through type erasure.
   List<Integer> a is non-reifiable
   List<?> b is NOT non-reifiable because it reverts to List<Object>

Non-reifiable types can not be used in instanceof expressions.

Heap pollution occurs when non-reifiable types refer to reifiable types, e.g. a = b and generate a compiler warning.

Java doesn't allow the creation of parameterized type arrays T[] t = new T[10]; generates a compiler error.

   @SafeVarargs
   <T> void setData(T... t) {
      ...
   }

Here T... is treated like T[] but compiles to Object[]. This code would generate a compiler warning if it weren't for the annotation.