Generics
Generics were introduced in the JDK 5.0 as a language enhancement. Generics are heavily used Java Collection Framework interface. Generics can be used to define methods, classes and interfaces that can operate with different data types.
Why Use Generics
- Generics provide compile-time safety
- Removes unnecessary type conversions
Generic Interfaces
Generics are defined with the type in angle brackets, <>
after the interface name.
Here is the definition of the java.util.Collection
interface
public interface Collection<E> extends Iterable<E>
<E>
defines the generic element that can passed to the Collection
. The collection can be used as follows to define a collection that can only contain String types :
Collection<String> collection;
or a collection that holds Integer types as follows :
Collection<Integer> collection;
We can replace <E>
in Collection<E>
with any type. We gain compile type safety checks from the compiler and also remove type conversion since we know the collection will always contain a specific type.
Generic Classes
Generic classes are defined the same way as generic interfaces. The type is specified in angle brackets, <>
.
Any ArrayList
is an ordered collection of objects by their index. Here is the definition of the ArrayList
generic class :
public class ArrayList<E> extends AbstractList<E> implements List<E>
Notice how the the class is defined with the <E>
, ArrayList<E>
and also inherits from a generic class and a generic interface. The <E>
defines the ArrayList
to be generic. It represents any element type. We can replace <E>
with any data type. Here is how we can declare a variable of the ArrayList
to hold Integer
types :
ArrayList<Integer> list;
and to hold String types :
ArrayList<String> list;
Instantiating Generic Classes
When instantiating a generic class we have to include the type in angle brackets, <>
.
Here is an example of instantiating the generic ArrayList
from above with types of String :
ArrayList<String> list = new ArrayList<String>();
Since we have already defined the type to be a generic String, we can replace the new ArrayList<String>()
with new ArrayList<>()
, since its redundant as follows :
ArrayList<String> list = new ArrayList<>();
We could also define an ArrayList
that can hold Integer types :
ArrayList<Integer> list = new ArrayList<>();
Using Generic Methods
Methods can also be declared to be generic by using the same E
specified in the generic class.
Here is the definition of the generic method add in the ArrayList
class :
public boolean add(E e){}
To use the generic method add
, we will have to pass in the correct type of E
.
ArrayList<Integer> list = new ArrayList<>();
list.add(10);
list.add(15.9); // compile type error
Notice the above generates a compile-time error when we try to pass in the wrong type. Without using generics the following will work :
ArrayList list = new ArrayList<>();
list.add(10);
list.add(15.9); // works without an error
The above works because we did not limit the types the ArrayList
can hold. The ArrayList
hold types of Object
. This code can cause run-time errors in future since we did not guarantee the types in the ArrayList
.