Chapter: Java The Complete Reference - The Java Language - Generics

Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail

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.

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.


Study Material, Lecturing Notes, Assignment, Reference, Wiki description explanation, brief detail


Copyright © 2018-2020 BrainKart.com; All Rights Reserved. Developed by Therithal info, Chennai.