Generic Methods

So far we have seen the wildcard feature used to give the methods you write some minimal knowledge about parameters that are generic types. You may be surprised (appalled, dismayed, horrified, or even delighted) to learn that individual methods can also be generic. In other words, there is a way to parameterize your methods with one or more type parameters.

As with classes, the type parameters are spelled out in angle brackets before the variable parameters. The type parameter comes immediately before the return type for the method, and after any access modifier. Here is the printFirst() method from the previous section rewritten to be a generic method:

public <T> void printFirst(LinkedList <T> e) { }

The generic parameter, T, comes before the method name to make the job of parsing easier for the compiler. It also separates the generic parameters away from the method signature. Once you have given names to the type parameters, like T here, you can use them in the argument list or the method body. Here we are using T to say that printFirst() takes an argument which is a LinkedList of T, whose name is e.

It may be that the return type uses the parameter type in some way, in which case you'll have two sets of angle brackets together, as in this example from the Java API:

static <T> Set<T> emptySet()

static

<T>

Set<T>

emptySet()

Modifiers

Generic parameter

Return type

Method signature

The method emptySet() has one type parameter, T, and it returns a value “set of T”.

Let's emphasize that this feature is intended for your methods that have parameters that are collection types. If you don't write code to pass around and process collection types, you probably won't need to use generic methods.

There's a difference between generic methods and generic classes. You never pass actual type arguments to a generic method, but you have to do this with a generic class. In the case of a generic method, the compiler looks at the types used in the method call, and figures out what actual type the generic type must be. The rule of thumb is that it chooses the most specific type argument that will make the call type-correct. So it would prefer Integer to Number, and it would prefer Number to Object.

Since we can implement some methods using either feature, wildcards or generics, you may wonder how to choose between them. Here are the guidelines.

  1. Choose wildcards when you want to convey the message “this method works on all the subtypes”. E.g. “this method works on a LinkedList of anything”. This is preferred over saying “this is a LinkedList of Object”.

  2. Sun advises that wildcards are “clearer and more concise” than generic methods, so wildcards are preferred when you have a choice.

  3. Use a generic method when you need to express a subtle connection or dependency between the argument types and/or the return type of a method. For example we mentioned above the generic method emptySet():

    static <T> Set<T> emptySet()

    Here the generic parameter is type <T> . The return type, which is Set<T>, depends on that type. We cannot express the return type except in terms of T. So this is a proper use of a generic method.

    If there is no such dependency, do not use a generic method.

Combining a generic method with a wildcard

Just when you thought it couldn't get any better, here comes the news that it's possible to combine a generic method with a wildcard. Here's the JDK 1.4 declaration of the static method Collections.copy().

static void copy(List dest, List src)

The copy() method copies all of the elements from the source list into the destination list. In JDK 1.5, the method changed to:

public static <T> void copy(List<? super T> dest, List<? extends T> src)

Breaking it down piece by piece,

  • copy() is a method with one generic parameter, T

  • copy() has two ordinary parameters, dest and src

  • dest can be a List of any type T or superclass of T

  • src can be a List of any type T or subclass of T

The thrust of that should jump off the page at you. It's saying when we assign “dest = src” the destination has to be a type that can hold the source. In other words, assignments like “ParentType = ChildType” are OK, but not the other way round.

That wraps up the last part of generic types, and how you will see them used in the class java.util.Collections. The rest of the chapter is dedicated to reviewing the Map interface and related types that store pairs of values.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.12.136.63