Java - Generics
We have seen as opposed to arrays, a List(or Collection) can hold multiple datatypes.
i.e we can insert an Integer or String or Float in the same List.
But this advantage can be a big disadvantage at times.
And thus Generics was introduced. It ensures type safety.
i.e. Just like Arrays it will be holding a single datatype at a time. Just see below:
List <String> arrayList = new ArrayList <String>();
i.e. The above created ArrayList will only be holding Strings. If we try to insert anything other than Strings it would end up with an error.
How Generics deals with Polymorphism ?
List <String> arrayList = new ArrayList <String>();
The above line of code is perfectly fine as, the generic type '<String> ' is in both sides. Now, let us consider the case of Animal and Dog relationship.
So, in the above case Animal is the parent of Dog. So can we write the below statement:
List <Animal> arrayList = new ArrayList <Dog> ();
Unfortunately the above doesn't work. If you are going to declare 'List <Animal> arrayList' then whatever is assigned to the List must be of generic type <Animal>.
List <Animal> arrayList = new ArrayList <Animal> ();
Story :
Let us consider a scenario. There is a God whose responsibility is to manage Animals(Be it a Cat, Dog e.t.c). And he has a behaviour manage().
We are really not concerned about what he manages. We just know his task is to manage only Animal and not Human or Fish.
class ManageAnimal{
public void manage(List <Animal> animal){
System.out.println("Manages in his own way");
}
}
The above method manage() will accept only a List on Animals. That is fine but look at the below problem.
public class TestManager{
public static void main(String[] args){
ManageAnimal manageAnimal = new ManageAnimal();
List <Dog> dogs = new ArrayList <Dog>();
dogs.add(new Dog());
dogs.add(new Dog());
manageAnimal.manage(dogs); // In this step the compiler throws an error.
}
}
In 'manageAnimal.manage(dogs);' the compiler throws an error. Any guesses why?
List <Animal> arrayList = new ArrayList <Dog>();
And even here we are trying to do the same.
i.e. Passing a list of Dog's(eg. List <Dog> dogs)
manageAnimal.manage(dogs);
to 'List <Animal> animal' in
public void manage(List <Animal> animal)
So, we change the above code in the below way:
public class TestManager{
public static void main(String[] args){
ManageAnimal manageAnimal = new ManageAnimal();
List <Animal> animal = new ArrayList <Animal>();
animal.add(new Dog());
animal.add(new Dog());
manageAnimal.manage(animal); // This works perfectly fine.
}
}
List <Dog> dogs = new ArrayList <Dog>();
List <Animal> animal = new ArrayList <Animal> ();
Then we are adding 'Dog' objects to the Animal reference. Thats perfectly fine.
As you pass 'ArrayList <Dog> ()', compiler will never end up with an error.
Wildcards :
In the above example we have seen, we cannot use the below line of code:
List <Animal> arrayList = new ArrayList <Dog>();
To solve the above problem java provides us with the wildcard (? extends) as shown below.
List <? extends Animal> animals = new ArrayList <Dog>();
The above line is selfexplanatory. It says we can add any subclass of Animal to the List.
So, let's modify the above example with the wildcard used.
class ManageAnimal{
public void manage(List <? extends Animal> animals){
//animals.add(new Dog()); // This line is not allowed.
System.out.println("Manages in his own way");
}
}
public class TestManager{
public static void main(String[] args){
ManageAnimal manageAnimal = new ManageAnimal();
List <Dog> dogs = new ArrayList <Dog>();
dogs.add(new Dog());
dogs.add(new Dog());
manageAnimal.manage(dogs); // There is no problem in this step.
}
}