Writing Generic Methods
In the previous section, we saw how to write Parameterized Classes. Now, let us spend time in exercising Parameterized Methods or Generic methods in this section. A Generic class containing a type parameter affects the entire class, but a generic method containing one or more type parameters affects that particular method only. So it means that a non-generic class can contain a mixture of generic and non-generic methods.Following code snippet shows how to declare a Generic method.
GenericMethods.java
package generics.methods;
public class GenericMethods
{
static <T> void printType(T anyType)
{
System.out.println(anyType.getClass().getName());
}
public static void main(String[] args)
{
GenericMethods.printType(String.class);
GenericMethods.printType(new String(""));
}
}
If we look at the way in which a Generic method is declared, we find that the static method printType()
has a return type void and it takes a single parameter called T
. Here T
stands for any parametric type which can be substituted with any of the Java types by the Clients. Since we have introduced a parameter T
, it should be defined. But where? It should be defined in the method definition itself just before the return type of the method (<T>). The moral is whenever we have different type parameters in a method, it should be defined in the method definition. For example, consider the following method that has two type parameters A and B and they are defined before the return type of the method separated by commas.
<A, B> void aGgenericMethod(A aType, B bType)
{
// Something here.
}
But the same type parameter can de used multiple number of times in the parameter list. For example, the type paramter A
is defined once but used multiple times in the following code, <A, B> void aGgenericMethod(A aType, A anotherType, B bType)
{
// Something here.
}
Wildcards
The following sections explain the usage of Wild-card character in Generics. For example, consider the following,List<String> strObjects = new ArrayList<String>();
The above line declares an Array List with a type being the String type. The declaration says that the list (strObjects
) in this case, can hold objects only of type java.lang.String
. No other type is permitted other than java.lang.String
. So, the following statements are legal as they are adding objects of type java.lang.String
. strObjects.add(new String("A String"));
strObjects.add(new String("Another String"));
Now, consider the following assignment statement which assigns the object reference strObjects
to anotherStrObjects
. Now anotherStrObjects
is pointing to strObjects
reference. List<String> anotherStrObjects = strObjects;
The above is a perfectly legal statement as the assignment happens between the same type. Now, consider the following, List<Object> objects = strObjects;
The above statement will lead to a compiler error telling that "Cannot convert from List<String> to List<Object". Though String
is a sub-class of the Object class, this type of conversion is not possible in Generics, but the following code compiles well. Object someObject = new String("");
The reason why it is not possible to assign the List containing strings to a List that can hold Objects can be given justification as follows. The main goal of having Generic code in a program is to ensure type-safety. It means that the expected Application types and the types sent by the Clients should match. There should not be any deviation or mis-match in their types. If we go back to the code, on the left-hand side, we have a List
that can hold Objects represented by List<Object>
objects. This tells to the compiler that this List can hold objects of type java.lang.Object
. Now we are making this object List to point to some other list whose parametric type is String
. Though String
is a concrete sub-class of Object
, this assignment is not possible. Let us see how to get over this problem. Consider the following code,
List<?> objects = strObjects;
The character '?'
is a wild-card character and it stands for any Java type. It can be java.lang.Object
type or some other type. It is just a place-holder that tells that it can be assigned with any type. Considering this case, the following are now valid syntaxes. List<?> anyObjects = null;
List<Integer> integers = new ArrayList<Integer>();
anyObjects = integers;
List<Double> doubles = new ArrayList<Double>();
anyObjects = doubles;
The above code snippet tries to assign a list of integers and a list of doubles to the reference anyObjects
. This is perfectly legal. Another strange thing has to be considered is while adding elements into the collection. Since the type parameter for the reference anyObjects is '?'
, no objects can be added to the collection, not even java.lang.Object
. The only exception is that only null
can be added to these type of collection. anyObjects.add(new Integer(1)); // Wont compile
anyObjects.add(new Double(1.0)); // Wont compile
anyObjects.add(null); // This will compile.
No comments:
Post a Comment