This tutorial is specifically designed with the intention to understand the creation of the generic class and how it works.
What is a generic class?
Java generic is a term that is used to denote a set of features which are related to the use of generic types and methods. A Generic class in java is nothing but an interface which one can parameterize for different types. We can follow the below format when it comes to defining a Generic class.
1
|
Class name<t1, t2,="" …tn=""> { /*…*/ }
|
The angle bracket defined above is basically used to specify the type parameters which are also known as type variables T1, T2..Tn.
We can customize the Java classes as well since we don’t have generics just limited to the predefined classes in the Java APIs. The below is an illustration of the declaration we learned above.
Listing 1: Customizing the Java classes
1
2
3
4
5
6
7
8
9
10
11
12
13
|
public class Generic<E> {
Class theClass = null ;
public Generic(Class theClass) {
this .theClass = theClass;
}
public E createInstance()
throws IllegalAccessException, InstantiationException {
return (E) this .theClass.newInstance();
}
}
|
What is <E>?
The alphabet E in the angle brackets displayed in the code above is a token that gives a hint that the class can have a type set once this is instantiated.
Let us understand the above said statement by using an example.
Listing 2: Defining type set
1
2
3
|
Generic<MyClass> = new Generic<MyClass>(MyClass.class);
MyClass myClassInstance = createInstance();
|
The main benefit of generic classes is that they are useful in early error detection at compile time. In order to get this benefit, we need to use a parameterized type such as LinkedList. This needs to be used in place of LinkedList and this will help the compiler to perform more type checks. This in turn requires lesser dynamic casts.
Using the above technique, it will be easier to detect the errors early since they will be reported at a compile time with the help of a compiler error message instead of getting an exception at run time.
Let us consider the example of LinkedList which is used to express the homogeneous list of elements. These homogenous lists of elements are of the type String.
Listing 3: Example of a parameterized type
1
2
3
|
LinkedList<String> list = new LinkedList<String>();
List.add(“abc”);
List.add( new Date());
|
Interfaces
In assition to classesclasses, we should also be aware of another hierarchy that is known by the name of interfaces which can be seen as a class specification. This however is not considered to be an implementation.
What does the interface lists?
An interface actually lists the method descriptors and not the actual code that are required by this interface. A class can always implement an interface by providing implementation to all methods declared in the interface. It is an interesting point to note that any class can be used to implement several interfaces and the only thing that is required to make this happen is the below method.
The advantage of using this method is that it helps the object to get compared -to other objects that are of the same type. The output of the above method could be in any form-positive, negative and even zero. This means the specified object here is either less than, greater than or equal to the object that is being passed as a parameter.
Generic type:
A generic type with formal type parameters is a declaration of a generic type with actual type of arguments. This is a reference type that has more than one parameter which are later replaced by type arguments the moment generic type is declared.
Listing 4: Example of a generic type
1
2
3
4
|
Public void add (E x);
Public Iterator iterator;
}
|
As discussed above the alphabet E in angle brackets is nothing but a place holder that will be later replaced by a type argument the moment generic type is declared.
Much on the similar lines of generic methods, the type parameter may comprise of more than one parameter that are separated by commas.
Why are these known as parameterized types? This is for the reason that they accept at least one parameter. Below is an example that illustrates this.
Listing 5: Example of a parameterized type
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
|
public class GenericClassExample<X> {
private X a;
public void set(X a) {
this .a = a;
}
public X get() {
return a;
}
public static void main(String[] args) {
GenericClassExample integerObj = new GenericClassExample<Integer>();
GenericClassExample stringObj = new GenericClassExample<String>();
integerObj.set( new Integer(50));
stringObj.set( new String( "Mrbool" ));
System.out.printf( "Integer Type Object's Value :%d\n\n" , integerObj
.get());
System.out.printf( "String Type Object's Value :%s\n" , stringObj.get());
}
}
|
The below Listing displays the output of the above code:
Listing 6: Output
1
2
|
Integer Type Object’s value: 50
String Type Object’s value: Mrbool
|
Here it can be observed that after the creation of a integer type object, the type of the variable X is modified to integer and same is the case with the String type .
We can use the below code to create a generic array with the following method signature.
Listing 7: Creating the generic array
1
2
3
4
5
6
7
|
public static T[] createArray(List list,Class ){
T[1..n] array = (T[]) Array.newInstance(class, list.size());
for (int i = 0; i < array.length; i++){
array[i] = list.get(i);
}
return array;
}
|
The point to note here is that we will not be able to make arrays and generics work together with current versions of Java and can only define arrays for non-generic types, and do casts in all the accessory.
Here in this tutorial so far we have defined a generic interface MyInterface and several classes that implement this interface. We would now be creating an array of the members of which can be assigned any object belonging to a class that implements the interface.
We can also make this happen by using an Object array. However this can lead to the loss of type information and then it needs to be cast each time we get something from the array. The other workaround of this could be to consider java.lang.reflect.Array.newInstance( Class C, int size ). But again this would require a single class C which would end up with an array that will allow assignments of C subclass objects.
The best way to do it is to use the wildcard HashMap[] x=new HashMap[3] and the prime reason behind this design is to maintain compatibility with existing code which is directly related to generics.
At the time of writing a generic which is nothing but a parameterized class, we have the class declaration that normally contains the type parameter in angle brackets. After this, we can have methods in a parameterized class which can make use of that parameter in the form of a return type. Also it can be used for its parameter types. As a result of this, we will observe that methods will view the type similar to concrete type because of its declaration in the class. The below example displays what we just discussed:
Listing 8: class declaration
1
2
3
4
5
6
7
|
public class LinkedList<A> {
...
public A getFront() { ... }
...
public void setFront(A a1) { ... }
...
}
|
Here is nothing but a type parameter that is normally passed to the class upon declaration. The point to note here is that A is being used as a return type for one method and a parameter type for another.
At the time of writing a parameterized code, we can also limit the range of acceptable types. This can be done with the introduction of a definite upper boundary which can be set so that only subtypes of that bound can be passed as the type parameter. In order to see the upper bound, we can make use of the extend keyword as shown below.
1
|
public class LinkedList<K extends Comparable> { ... }
|
We can see that any class that is normally used to implement the interface Comparable can accept this implementation of LinkedList.
It is a must to specify the type parameter whenever an instance of a parameterized object is created and the below example explains this.
1
|
LinkedList<String> _list = new LinkedList<String>();
|
The objective of the above code is to create a LinkedList. This can only be used to contain String objects and then we will have the compiler check that the actual type which in this case is a String is a subtype of the bound of the type parameter. Otherwise, the code will not compile.
Conclusion
We learned several techniques to create Generic Java classes . Hope you liked the article.
You must be logged in to post a comment.