Generics was introduced in Java in its version (1.)5. These are erased during compilation, so runtime reflection is not possible for them. Generics generate new types parametrized by other types. For example we do not have to create new classes in order to use type safe collection of String
s and Number
s, generic ArrayList<T>
can be used in all cases, like: new ArrayList<String>()
.
Example:
List<String> variable = new ArrayList<String>();
In Java 7 some syntactic sugar was introduced to ease the construction (<>
aka. diamond):
List<String> variable = new ArrayList<>();
Interestingly it was also possible (from Java 5) to use type inference, when a static method had as a return value (often used in Google Guava for example):
List<String> singleton = Collections.singletonList();//Note the missing `<>` or `<String>`!
In Java existential types were used to provide polymorphism for the types, as the generic types are invariant (for example: List<String>
is not a subtype, nor a supertype of List<CharSequence>
, although in Java String[]
is a subtype of CharSequence[]
; note: String
implements the CharSequence
interface). Existential generic types can be expressed as:
List<? extends CharSequence> list = new ArrayList<String>();
Comparable<? super ChronoLocalDate> ccld = LocalDate.now();
ChronoLocalDate cld = JapaneseDate.now(); //ChronoLocalDate extends Comparable<ChronoLocalDate>
ccld.compareTo(cld);
//cld.compareTo(ccld);//fails to compile because ccld is not a `ChronoLocalDate` (compile time)
Both instances can be used in a list parametrized by the corresponding Comparable
:
List<Comparable<? super ChronoLocalDate>> list2 = new ArrayList<>();
list2.add(cld);
list2.add(ccld);