-- With generics, we can create type-safe collections where more problems are caught at compile-time instead of runtime
-- With generics, we are prevented at compile time from putting the wrong type of object into a container
-- Without generics, the compiler would let us put any type of object into a collection
-- There are three important places where generics are used
o Creating instances of generified classes
new ArrayList<String>()
o Declaring and assigning variables of generic types
List<String> names = new ArrayList<String>()
o Declaring and invoking methods that take generic types
void foo(List<String> list) {
//method code
}
x.foo(names)
-- The java documentation defines the ArrayList as
public class ArrayList<E> extends AbstractList<E>
implements List<E> {
public boolean add(E o) {
//method code
}
//other ArrayList methods
}
-- In the above definition "E" represents the type used to create an instance of ArrayList
-- "E" is just a stand-in for the type of element we want this collection to hold and return
-- For instance, if we declare the ArrayList as
ArrayList<String> thisList = new ArrayList<String>();
-- The compiler interprets it as
public class ArrarList<String> extends AbstractList<String>
implements List<String> {
public Boolean add(String o) {
}
}
-- In other words, the "E" is replaced by the real type that is used when the ArrayList is created
-- A generic class means that the class declaration includes a type parameter
-- A generic method means that the method declaration uses a type parameter in its signature
-- When you declare a type parameter for the class, you can simply use that type any place that you'd use a real class or interface type
public class MyClass<E> extends MySuperClass<E> {
//in the following method declaration "E" simply
//represents the type parameter defined in the
//class declaration above
public void myMethod(E o) {
}
}
-- We can also define a type parameter as part of method definition, even if the type parameter was defined in the class declaration
public <T extends Animal> void takeThing(ArrayList<T> list) {
}
-- In the above example, "T" used as the type for argument ArrayList is the type defined in the method signature
-- When we say "extends" in the above code, it really means "extends or implements"
-- In generics, the keyword "extends" really means is-a and works for both classes and interfaces
-- The type specified to the right of "extends" can either be a class or an interface
-- If the class itself doesn't use a type parameter, we can still specify one for a method, by declaring it before the return type
public void takeThing(ArrayList<Animal> list) {
}
-- The above code is really different from the earlier one
-- In the first case, the type can be "Animal" or any subclass of "Animal"
-- In the second case, the type has to be strictly "Animal", using a subclass of "Animal" will cause a compiler error
-- If the compiler does allow an ArrayList of subclass say Cat, of Animal to be passed in the second case, then it will cause problems if we try to add a Dog object another subclass of Animal, to the ArrayList passed as parameter
-- If the parameter were an array of "Animal" objects, then we can very well pass an array of "Cat" objects to the method
-- This is because Array types are checked again at runtime, but collection type checks happen only at compile time
-- Hence if we try to add a Dog object to a Cat Array passed as parameter, the compiler will throw a runtime error
-- If we do need to make the method argument accept a subclass of the given type, we can use a wildcard
public void takeThing(ArrayList<? extends Animal> animals) {
}
-- Now we can very well pass an ArrayList of Cat to the method
-- But when we use a wildcard in the method argument, the compiler will not let us add any element to the list
-- We can call other methods on the argument but we can't add a new element to the ArrayList
public void takeThing(ArrayList<? extends Animal> animals) {
for(Animal a : animals)
a.eat(); à this works
a.add(new Cat()); à this won't work
}
-- Using the wildcard is the same as using the following
public <T extends Animal> void takeThing(ArrayList<T> list) {
}
No comments:
Post a Comment