You are on page 1of 8

Generics

Generics in 5-Minutes

List<String> myList = new ArrayList<String>();

We can put an Animal(Object) and its subtype to List of generic type


Animal(Object).

Polymorphism applies to the "base" type of the collection, not in Generic


type.
List<JButton> myList = new ArrayList<JButton>(); //Correct.
List<Object> myList = new ArrayList<JButton>(); //Wrong

You can't pass an ArrayList<Dog> to an argument of ArrayList<Animal>.


It is dangerous to pass a collection (array or ArrayList) of a subtype into a
method that takes a collection of a supertype, because you might add something
wrong.

This works with arrays because there is a runtime exception


(ArrayStoreException) that will prevent you from putting the wrong type of
object into an array. But there IS no equivalent exception for generics,
because of type erasure!
At runtime the JVM KNOWS the type of arrays, but does NOT know the type of a
collection.
There are no type information at runtime, To support legacy code.
Remember, Generic code is strictly for the compiler.

There is a wayto get around it. i.e. You can pass an ArrayList<Dog> to an
argument of ArrayList<Animal> with some manipulation in generic.

List<? extends Animal> animalList; declaration implies :


 animalList accept any object of type <Animal> or anything that extends
Animal. And
 animalist will not #ADD# anything into it.

List<? super Dog>animalsList; declaration implies :


 animalsList can accept the type on the right-hand side of super or any
of its supertypes,
 Nothing lower in the inheritance tree can come in.
 And you can add anything which is Dog or super of Dog.

Generic class declaration:


Class TestGenerics<T> { }
The <T> is a placeholder for the type you pass in.

Generic method declaration


You can define a parameterized type (instance of any type) at a method level,
without being class generic.
Public <T extends Number> void restrcitedArrayList(T t){
List<T> list = new ArrayList<T>();
}
Details

Java 5 onwards we have generics. They aren't only for making type safe
collections but collections as the overwhelming reason and motivation
for adding generics to the language.
By using generics syntax—which means putting the type in angle
brackets <String>, we're telling the compiler that this collection can
hold only String objects.So, now
 That what you put IN is guaranteed,
 You can also guarantee what comes OUT, and
 That means you can get rid of the cast when you get something
from the collection.

Pre-generics, when a String wasn't guaranteed.


String s = (String)myList.get(0);
Now we can just say
String s = myList.get(0);

The compiler already knows that myList contains only things that can
be assigned to a String reference, so now there's no need for a cast.
You can declare a type parameter for a method argument, which then
makes the argument a type safe

reference:

Void takeListOfStrings(List<String> strings) {


strings.add(new Integer(42)); // NO!! strings is type safe
}

Return types can obviously be declared type safe as well:


The compiler will stop you from returning anything not compatible with
a returned object.And since the compiler guarantees that only a type
safe Dog Set is returned, those calling the method won't need a cast
to take Dogs from the Set:

Dog d = getDogList().get(0);

To update non-generic code to make it generic.


 just add a type in angle brackets (<>) immediately following the
collection type in BOTH
the variable declaration and
The constructor call.
List myList = new ArrayList(); //non generic
List<Integer>myList = new ArrayList<Integer>(); //generic

 Including any place you declare a variable, so that means


arguments and
return types too. Thats it.
public List changeStrings(ArrayList s) { } //non-generic
public List<String> changeStrings(ArrayList<String> s) { } ///generic
If there's code that used the earlier non-generic version and
performed a cast to get things out, that won't break anyone's code.

We can put an Animal and its subtype to List of generic type Animal.
List<Animal> animalList = new ArrayList<Animal>();
animalList.add(new Animal("No Name"));
animalList.add(new Dog("Jimmy A Dog"));

Challenges :
How to deal with legacy code built without generics?

Polymorphism

Polymorphism applies to the "base" type of the collection, not in


Generic type.
Ex: List<Integer> myList = new ArrayList<Integer>();
BaseType is List and ArrayList.
Generictype is the object inside <>, here Integer.

polymorphism applies to only the "base" type not on generic type.


List<JButton>myList = new ArrayList<JButton>(); //Correct.
List<Object>myList = new ArrayList<JButton>(); // Wrong!

JButton is the generic type

This is NOT how it works with arrays :


Object[] myArray = new JButton[3]; // Correct
List<Object> list = new ArrayList<JButton>(); // Wrong!

Why can't you pass an ArrayList<Dog> to an argument of


ArrayList<Animal>?
And why is it bad for ArrayList but not for arrays?
Actually, the problem IS just as dangerous whether you're using arrays
or a generic collection. It's just that the compiler and JVM behave
differently for arrays vs. generic collections.

The reason it is dangerous to pass a collection (array or ArrayList)


of a subtype into a method that takes a collection of a supertype, is
because you might add something. And that means you might add the
WRONG thing!
The reason you can get away with compiling this for arrays is because
there is a runtime exception (ArrayStoreException) that will prevent
you from putting the wrong type of object into an array.
If you DO try to add a Cat to the object that is actually a Dog array,
you'll get the exception. But there IS no equivalent exception for
generics, because of type erasure!
In other words, at runtime the JVM KNOWS the type of arrays, but does
NOT know the type of a collection.
So remember
Polymorphism applies to only the "base" type not on generic type.

Lets say we can pass ArrayList<Dog> to an argument ofArrayList<Animal>.

Public void addAnimal(List<Animal> animals) {


animals.add(new Dog()); // The code above WILL compile just fine.
animals.add(new Cat());
}

So following code is true –


List<Dog> dog = new ArrayList<Dog>();
dog.add(new Dog());
addAnimal(dog);

This implies we are adding into the Dog list a Cat.


That is contradictory by the definition of generic.
Definition – In List<Dog> dog we can add only dog object or its child.

Type Erasure
At runtime, ALL collection code—both legacy and generics—looks exactly like
the pre-generic version of collections. None of typing information exists at
runtime.Through a process called "type erasure," the compiler does all of its
verifications on your generic code and then strips the type information out of
the class bytecode.
Generic code is strictly for the compiler.

Why is there no type information at runtime?


To support legacy code.
At runtime, collections are collections just like the old days.What you gain
from using generics is compiletime protection that guarantees that you won't
put the wrong thing into a typed collection.

List<Animal>myList = new ArrayList<Animal>(); //Correct *


List<Animal>myList = new ArrayList<Dog>(); // Wrong
Here,
generic type -> Animal
Base Type ->myList

How do you get around it?

List<? extends Animal> animalList; declaration implies :


 animalList accept any object of type <Animal> or anything that
extends Animal. And
 animalList will not #ADD# anything into it.

List<? extends Animal>aList = new ArrayList<Dog>();


Note :
List<? extends Animal>aList = new ArrayList<? extends Animal>();
This is wrong. Constructor doesn’t accepts.
Use Case :
mostly passed as function parameter.
Zoo(List<? extends Animal>animalList){ }
This can be called as
List<Dog>dogList = new ArrayList<Dog>();
Zoo(dogList);

List<Cat>catList = new ArrayList<Cat>();


Zoo(catList);

List<? super Dog>animalsList; declaration implies :


 animalsList can accept the type on the right-hand side of super
orany of its supertypes,
 Nothing lower in the inheritance tree can come in.

List<? super Dog>aList = new ArrayList<Animal>();


Use Case :
-mostly passed as function parameter, as above.
Zoo(List<? Super Animal>animalList){ }
This can be called as
Zoo(objList);
//where List<Object>objList = new ArrayList<Object>();
Zoo(AnimalList);
//where List<Animal>AnimalList = new ArrayList<Animal>();
Generic class declaration :

classTestGenerics <T> { }
The <T> is a placeholder for the type you pass in.
T stands for "type", but any valid Java identifier would work here.

Class TestGenerics<T> {

T anInstance;
T[] listofT;

TestGenerics(T anIns){
anInstance = anIns;
}

T getInstance(){
Return anInstance;
}
}

class Zoo<T extends Animal> { // use "T" instead of "?"


T animal;
Zoo(T animal){
this.animal = animal;
}

T getInstance(){
returnanimal;
}
}

Generic Methods
It's possible to define a parameterized type (instance of any type) at
a method level,without being class generic.

BURN IT IN MIND :
In order to use a type variable <T>, you must declared it either
 As the class parameter type or
 In the method, before the return type.

It’s tempting to forget that the method argument is NOT where you
declare the type parameter variable T.

Public <T> void makeArrayList(List<T> list) {


List<T> list1 = new ArrayList<T>();
list1.addAll(list);
}

Public <T extends Number> void restrciedArrayList(T t){


List<T> list = new ArrayList<T>();
list.add(t);
}

You might also like