Creating a Generic Method
As the preceding examples
have shown, methods inside a generic class can make use of a class’ type
parameter and are, therefore, automatically generic relative to the type
parameter. However, it is possible to declare a generic method that uses one or
more type parameters of its own. Furthermore, it is possible to create a
generic method that is enclosed within a non-generic class.
Let’s begin with an example.
The following program declares a non-generic class called GenMethDemo and a static generic method within that class called isIn( ). The isIn( ) method determines if an object is a member of an array. It
can be used with any type of object and array as long as the array contains objects
that are compatible with the type of the object being sought.
// Demonstrate a simple generic method.
class GenMethDemo {
// Determine if an object is in an array.
static <T extends Comparable<T>, V
extends T> boolean isIn(T x, V[] y) {
for(int i=0; i < y.length; i++)
if(x.equals(y[i])) return true;
return false;
}
public static void main(String args[]) {
// Use isIn() on Integers.
Integer nums[] = { 1, 2, 3, 4, 5 };
if(isIn(2, nums)) System.out.println("2 is
in nums");
if(!isIn(7, nums))
System.out.println("7 is not in
nums"); System.out.println();
// Use isIn() on Strings.
String strs[] = { "one",
"two", "three", "four", "five" };
if(isIn("two", strs))
System.out.println("two is in strs");
if(!isIn("seven", strs))
System.out.println("seven is not in strs");
//Oops! Won't compile! Types must be
compatible.
if(isIn("two", nums))
System.out.println("two is in strs");
}
}
The output from the program
is shown here:
2 is in nums
7 is not in nums
two is in strs
seven is not in strs
Let’s examine isIn( ) closely. First, notice how it
is declared by this line:
static <T extends Comparable<T>, V
extends T> boolean isIn(T x, V[] y) {
The type parameters are
declared before the return type of
the method. Also note that
T extends Comparable<T>. Comparable is an interface declared in java.lang. A class that implements Comparable defines objects that can be ordered. Thus, requiring an
upper bound of Comparable ensures
that isIn( ) can be used only with
objects that are capable of being compared. Comparable is generic, and its type parameter specifies the type of
objects that it compares. (Shortly, you will see how to create a generic
interface.) Next, notice that the type V
is upper-bounded by T. Thus, V must either be the same as type T, or a subclass of T. This relationship enforces that isIn( ) can be called only with
arguments that are compatible with each other. Also notice that isIn( ) is static, enabling it to be
called independently of any object. Understand, though, that generic methods
can be either static or non-static. There is no restriction in this regard.
Now, notice how isIn( ) is called within main( ) by use of the normal call
syntax, without the need to specify type arguments. This is because the types
of the arguments are automatically discerned, and the types of T and V are adjusted accordingly. For example, in the first call:
if(isIn(2, nums))
the type of the first
argument is Integer (due to
autoboxing), which causes Integer to
be substituted for T. The base type
of the second argument is also Integer,
which makes Integer a substitute for V, too. In the second call, String types are used, and the types
of T and V are replaced by String.
Although type inference will
be sufficient for most generic method calls, you can explicitly specify the
type argument if needed. For example, here is how the first call to isIn( ) looks when the type arguments
are specified:
GenMethDemo.<Integer, Integer>isIn(2,
nums)
Of course, in this case,
there is nothing gained by specifying the type arguments. Furthermore, JDK 8
has improved type inference as it relates to methods. As a result, there are
fewer cases in which explicit type arguments are needed.
Now, notice the commented-out
code, shown here:
if(isIn("two", nums))
System.out.println("two is in strs");
If you remove the comments
and then try to compile the program, you will receive an error. The reason is
that the type parameter V is bounded
by T in the extends clause in V’s
declaration. This means that V must
be either type T, or a subclass of T. In this case, the first argument is
of type String, making T into String, but the second argument is of type Integer, which is not a subclass of String. This causes a compile-time type-mismatch error. This ability to enforce type safety is
one of the most important advantages of generic methods.
The syntax used to create isIn( ) can be generalized. Here is the
syntax for a generic method:
<type-param-list > ret-type
meth-name (param-list) { // …
In all cases, type-param-list is a comma-separated
list of type parameters. Notice that for a generic method, the type parameter
list precedes the return type.
Generic
Constructors
It is possible for
constructors to be generic, even if their class is not. For example, consider
the following short program:
// Use a generic constructor.
class GenCons {
private double val;
<T extends Number> GenCons(T arg) { val =
arg.doubleValue();
}
void showval() { System.out.println("val:
" + val);
}
}
class GenConsDemo {
public static void main(String args[]) {
GenCons test = new GenCons(100);
GenCons test2 = new GenCons(123.5F);
test.showval();
test2.showval();
}
}
The output is shown here:
val: 100.0 val: 123.5
Because GenCons(
) specifies a parameter of a generic type, which must be a subclass of Number, GenCons( ) can be called with any numeric type, including Integer, Float, or Double.
Therefore, even though GenCons is
not a generic class, its constructor is generic.
Related Topics
Privacy Policy, Terms and Conditions, DMCA Policy and Compliant
Copyright © 2018-2023 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.