Java Generics

Basics

  • Generics is a compile time safety in Java rather than a runtime feature!
  • Generics enable types (classes and interfaces) to be parameters when defining classes, interfaces and methods. It removes casting too.
  • A type variable can be any non-primitive type: any class type, any interface type, any array type, or even another type variable.
  • List<E> is a generic interface that takes a type parameter - in this case, E.
  • <> is called diamond operator.
  • The most commonly used type parameter names are:E - Element, K - Key, N - Number, T - Type, V - Value, S,U,V etc. for 2nd, 3rd, 4th types, etc.
  • In JDK 5.0 the class java.lang.Class is generic. The type T in Class stands for the type that the Class object is representing. For example, the type of String.class is Class<String>, and the type of Serializable.class is Class<Serializable>.

Raw and Parameterized

  • List<String> is a parameterized type, and List alone is a raw type. Avoid mixing them together in the code. A non-generic class or interface type is not a raw type.
  • The raw type 'List' is not the same as the parameterized type List<Object>!

Bounds

  • A bounded type parameter is useful to impose restrictions on the types we want. List<T extends Number> only accepts numbers.
  • A type parameter can have multiple bounds: <T extends B1 & B2 & B3>

Wildcards

  • List<?> is a special kind of parameterized type known as a wildcard type. It is read a list of unknowns; a list whose element type matches anything.
  • bounded wildcards: public void drawAll(List<? extends Shape> shapes) { … }

Wildcards with a lower bound

The syntax ? super T denotes an unknown type that is a supertype of T (or T itself; remember that the supertype relation is reflexive). It is the dual of the bounded wildcards we've been using, where we use ? extends T to denote an unknown type that is a subtype of T.

public static <T> T writeAll(Collection<T> coll, Sink<? super T> snk) {

This is an example of giving multiple bounds for a type parameter:

public static <T extends Object & Comparable<? super T»
T max(Collection<T> coll)

Generics and Subtypes

  • Given two concrete types A and B (for example, Number and Integer), MyClass<A> has no relationship to MyClass<B>, regardless of whether or not A and B are related. The common parent of MyClass<A> and MyClass<B> is Object. So if B extends A then MyClass<B> will NOT extend MyClass<A>. List<String> is not a subset of List<Object>.
  • You can subtype a generic class or interface by extending or implementing it. The relationship between the type parameters of one class or interface and the type parameters of another are determined by the extends and implements clauses. so ArrayList<A> is a subtype of List<A> is a subtype of Collection<A>.

Collection<Object> is not the parent of all collections but Collection<?> is and called the collection of unknowns. This is a wildcard type.

List<?> c = new ArrayList<String>();
c.add(new Object()); // Compile time error
Object v = c.get(0); //ok

The add() method takes arguments of type E, the element type of the collection. When the actual type parameter is ?, it stands for some unknown type. Any parameter we pass to add would have to be a subtype of this unknown type. Since we don't know what type that is, we cannot pass anything in. 

for get() method, the result type is an unknown type, but we always know that it is an object. It is therefore safe to assign the result of get() to a variable of type Object or pass it as a parameter where the type Object is expected.

Casting

Type variables should not be used in casts. It makes no sense as they do not exist in runtime.

Collection cs = new ArrayList<String>();
// compile error
if (cs instanceof Collection<String>) { ... }
 
//this is ok
if(cs instanceof Collection<?>)
 
// Unchecked warning,
Collection<String> cstr = (Collection<String>) cs;
 
// Unchecked warning. 
<T> T badCast(T t, Object o) {
    return (T) o;
}

Arrays

The component type of an array object may not be a type variable or a parameterized type, unless it is an (unbounded) wildcard type. You can declare array types whose element type is a type variable or a parameterized type, but not array objects.

//not allowed
List<String>[] lsa = new List<String>[10];
List<String>[] lsa = new List<?>[10];

//allowed
List<?>[] lsa = new List<?>[10];

Generic Methods

  • Just like type declarations, method declarations can be generic - that is, parameterized by one or more type parameters.
static <T> void fromArrayToCollection(T[] a, Collection<T> c) {     //the <T> before void indicated the types used in params
    for (T o : a)
    c.add(o);     // correct
}
 
//Instead of :
 
static void fromArrayToCollection(Object[] a, Collection<?> c) {
    for (Object o : a) 
    c.add(o);         // compile time error
}
  • Below method declarations are all valid:
<T> void save(T entity);
<T,Z> Z get(Class clazz,T id);
public <T extends E> boolean addAll(Collection<T> c);         // type variables can have bounds too!
private <X, Y> EnumConverter<X, Y> register(ConverterKey<X, Y> bKey);
private <A, B> void register(EnumConverter<A, B> c);
public <A, B> B register(A fromObject, Class<B> toClass);
public <T> List<T> register(Class<T>c, Query query);
public <T> T register(Class<T>c, Query query);

Generic Class

When initializing a generic class, if you do not use the generic type then all the generic type in the whole class will be ignored.

class name<T1, T2, ..., Tn>
 
public class Test<T> {
    T get(){
 
    }
}
 
Test t = new Test();//this is not good as all the occurrences of T in the class will be ignored
Test t = new Test<String>();//this is cool

From Java 7 you can replace the type arguments required to invoke the constructor of a generic class with an empty set of type arguments (<>) as long as the compiler can determine, or infer, the type arguments from the context: Map<String, List<String» myMap = new HashMap<>();

Unless otherwise stated, the content of this page is licensed under Creative Commons Attribution-ShareAlike 3.0 License