JAVA GENERICS
untill 1.4v a non-generic version of ArrayList class is declared as follows.
Class ArrayList
{
add(Object o);
Object get(int index);
}
The return type of get is object and the argument add(-) is method is object. Hence we can add any type of object to the ArrayList due to this we are missing type safety.
The return type of the get method is object. and hence at the time of retrieval we have to perform type casting.
But in 1.5 v A generic version of ArrayList class is declared as follows
Ex: class ArrayList<T>
{
add(T k);
T get(int index);
}
here 'T' is Type parameter
add(-) take T type of argument and the return type of get(-) is 'T'.
Based on our requirement 'T' will be replaced with corresponding type.
For Ex: to hold only String type of object a generic Version of ArrayList object can be created as follows
ArrayList<String> l=new ArrayList<String>();
For these requirement compiler considered version of ArrayList class is as follows.
Class ArrayList<String>
{
add(String s);
String get(int index);
}
The argument to add(-) is String and hence we can add only String type of objects to the list. by mistake if we are trying to add any other type we will get compile time error.
Ex: l.add("SCJP");//valid
l.add(new Integer(10));//invalid
CE: can't find the symbol
Symbol: method add(Integer)
location: class ArrayList<String>
The return type of get(-) method is String and hence at the time of retrieval it is not required to perform any typecasting.
In generics we are associating type parameter for a class such type of parameterized class is nothing but generic class.
Generics concept is applicable for our own classses also. hence based on our requirement we can create our own generic class
Generics concept is applicable for our own classses also. hence based on our requirement we can create our own generic class
Class Account<T>
{..
.
}
Account<Gold> a1=new Account<Gold>();
Account<Silver> a2=new Account<Silver>();
Ex: class Gen<T>
{
T obj;
T obj;
Gen(T ob)
{
this.obj=ob;
}
public void show(){
sop("The type of ob"+obj.getClass().getName());
}
public T getObj()
{
return obj;
}
}
class GenDemo
{
p s v main(-){
//For String type
Gen<String> g1=new Gen<String>("SCJP");
g1.show();//The type of the obj: java.lang.String
g1.getObje();//SCJP
//For Integer Type
Gen<Integer> g1=new Gen<Integer>(10);
g1.show();//The type of the obj: java.lang.Integer
g1.getObje();//10
//For Double
Gen<Double> g1=new Gen<Double>(11.5);
g1.show();//The type of the obj: java.lang.Double
g1.getObje();//11.5
}
}
Bounded Types:
we can bound the type of parameter for a particular range by using extends keyword such types are called Bounded types.
Ex: class Test<T>
{
....
}
For the type parameter we can provide any type and there are no restrictions hence it is unbounded type
Ex : Test<String> t1=new Test<String>("SCJP");
Test<Integer> t1=new Test<Integer>(10);
class Test<T extends X>
{...
..
}
here 'X' is a class/interface
- if 'X' is a class then as the type parameter we can take either 'X' or its children
- if 'X' is an interface. then as the type parameter we can pass either 'x' type or its implementation classes.
{
Test<Integer> t1=new Test<Integer>;//valid
Test<String> t1=new Test<String>("SCJP");//invalid
CE: type parameter java.lang.String is not within its bound
--> class Test<T extends Runnable>
{..
..
}
Test<Runnable> t1=new Test<Runnable>();//valid
Test<Thread> t2=new Test<Thread>();//valid
Test<String> t3=new Test<String>();//Invalid
CE: Type parameter java.lang.String is not within its bound
Note 1: instead of type parameter 'T' we can use any valid java identifier but it is convention to use 'T'
class Test<T>{} class Test<X>{} class Test<SCJP>{}
here all are valid only.
2. we can pass more than one type parameter also based on our requirement.
class Test<X,Y,Z>{}
class HashMap<K,V>{} here K is key, V is Value
HashMap<String,Integer> h=new HashMap<String,Integer>();
3. we can bound the type parameter.even in combination also
Ex ; class Test<T extends Number & Runnable>
{
}
as the type parameter we can pass any type which should be child class of Number and implements Runnable interface.
<T extends Runnable & Comparable> //valid
<T extends Number & Runnable & Comparable>//valid
<T extends Runnable & Number>//invalid we have to take class first and then interfaces next
<T extends Number & Thread>//invalid we can't extend more than one class at a time.
note : we can bound the type parameter only by using extend keyword and it is not possible to bound by using implements and super keywords. but implements keyword purpose we can replace with extends keyword.
Ex: class Test<T extends Number>{}
class Test<T implements Runnable>{}//invalid
class Test<T extends Runnable>{};//valid
class Test<T super String>{}//invalid
-->Wild Character(?:)
1. m1(ArrayList<String> l):
we can call this method by passing arraylist of only "String" type.
but within the method we can add only String and 'null' to the list.
m1(ArrayList<String> l)
{
l.add("A");
l.add("B");
l.add("C");
l.add(null);
l.add(10);//invalid
}
2. m1(ArrayList<?:> l)
here we can call this method by passing Arraylist of any type.
But within the method we can't add anything except "null" to the list because we don't know the type of 'l' exactly
Ex: m1(ArrayList<?:> l)
{
l.add(10);//invalid
l.add("scjp");//invalid
l.add(null);//valid
}
This type of methods are best suitable for Read operation.
3. m1(ArrayList<?: extends X> l):
'X' can be a class or Interface.
if 'X' is a class then this method is applicable for ArrayList of either X or its child classes
if 'X' is an interface then this method is applicable for ArraList of either 'X' or its implementation classes
here within the method we can't write any thing to the list except 'null' because we don't know the type of the list 'exactly'.
This type of method also best suitable for Read operations.
4. m1(ArraList<?: super X>:
if 'X' is a class then this method is applicable for ArrayList of either 'X' type or its super classes
if 'X' is an interface this method is applicable for ArrayList of either 'X' type or superclasses of implementation classes of 'X'.
Ex: Thread extends object and implements Runnable
but within the method we can add 'X' type of objects and null to the list.
Valid or invalid:
ArrayList<String> l=new ArrayList<String>();//valid
ArrayList<?> l=new ArrayList<String>();//valid
ArrayList<? extends Number> l=new ArrayList<integer>();//valid
ArrayList<?> l=new ArrayList<Integer>();//valid
ArrayList<? extends Number> l=new ArrayList<String>();/invalid
CE: incompatible types
found: ArrayList<String>
required: ArrayList<? extends Number>
ArrayList<? super String> l=new ArrayList<String>();//valid
ArrayList<? super String> l=new ArrayList<Object>();//valid
ArrayList<?> l=new ArrayList<? extends Number>();//in valid
CE: unexpected type
found: ?
required : class/interface without bounds
ArrayList<?> l=new ArrayList<?>();//in valid
CE: unexpected type
found: ?
required : class/interface without bounds
-->Generic Method:
we can declare the type parameter either at class level or at method level.
Declaring type parameter at class level:
we have to declare the type parameter after class name
class Test<T>
{
use 'T' anywhere based on our requirement within this class
}
Declaring type parameter at method level:
we have to declare the type parameter just before return type
class Test{
public <T> void m1(T k)
{
use 'T' anywhere within the method
}
}
Valid or invalid:
<T extends Number>//valid
<T extends Runnable>//valid
<T extends Number & Runnable>//valid
<T extends Runnable&Number>//invalid
<T extends Number & Thread>//invalid
Communication with the Non-generic Code:
whenever we are sending generic objects to non-generic area then generic properties will be lost.
class Test{
p s v main(-){
//Generic Area
ArrayList<String> al=new ArrayList<String>();
l.add("A");//valid
l.add("B");//valid
l.add("C");//valid
//l.add(10);CE:
m1(l);
syso(l);[A,B,C,10,10.5,true]
//l.add(20);//CE
}
public static void m1(ArrayList l)
{
//Non Generic Area
l.add(10);//valid
l.add(10.5);//valid
l.add(true);//valid
}
l.add(true);//valid
}
}
Conclusions:
- Generics concept is applicable only at compile time at run time there is no such type of concept.hence the following declarations are equal
ArrayList l=new ArrayList();
ArrayList l=new ArrayList<String>();
ArrayList l=new ArrayList<Integer>(); - Ex: ArrayList l=new ArrayList<String>();
l.add(10);
l.add(10.5);
l.add(true);
l.add(11);
sop(l);[10,10.5,true]
The following true declarations are equal
ArrayList<String> l=new ArrayList<String>();
ArrayList<String> l=new ArrayList();
for these list objects we can add only "String" type of objects.
Ex: class Test
{
public void m1(ArrayList<String> l)
{
}
public void m1(ArrayList<Integer> l)
{
}
}
CE: name clash: both methods having same erosure.(syntax of method excluding arraylist part)
ArrayList<String> l=new ArrayList<String>();
ArrayList<String> l=new ArrayList();
for these list objects we can add only "String" type of objects.
Ex: class Test
{
public void m1(ArrayList<String> l)
{
}
public void m1(ArrayList<Integer> l)
{
}
}
CE: name clash: both methods having same erosure.(syntax of method excluding arraylist part)
Comments
Post a Comment