Java Generic Methods

Jakob Jenkov
Last update: 2024-07-06

Java Generics can be used with Java methods. In other words, it is possible to generify methods in Java. More specifically, you can specify generic types for parameters as well as return types of Java methods.

Here is a Java generic method example:

public static <T> T addAndReturn(T element, Collection<T> collection){
    collection.add(element);
    return element;
}

This Java method specifies a generic type T which is used both as type for the element parameter and the generic type of the Collection. Notice how it is now possible to add elements to the collection. This was not possible if you had used a Java generics wildcard in the Collection parameter definition.

So, how does the Java compiler know the type of T?

The answer is, that the Java compiler infers this from your use of the method. For instance:

String stringElement = "stringElement";
List<String> stringList = new ArrayList<String>();

String theElement = addAndReturn(stringElement, stringList);    

In this example the Java compiler will infer the type T to be String, since String is the type of the first object passed as parameter to the addAndReturn() method, and String is also the generic type parameter for the collection passed as the second parameter to addAndReturn().

We can use addAndReturn() as it is with other types too. No changes necessary.

In this example we are using the addAndReturn() method with an Integer object and a List with the generic type of Integer too:

Integer integerElement = new Integer(123);
List<Integer> integerList = new ArrayList<Integer>();

Integer theElement = addAndReturn(integerElement, integerList);    

Just like with the previous example the Java compiler will infer the generic type of addAndReturn() to be Integer, because that is the type of both the first parameter passed to addAndReturn() , and it is also the generic type parameter of the List passed as second parameter.

As you can see, the exact same method can be used in a type safe manner with different types! The Java compiler will simply infer what types the method should work on from how you use the method in your code (return types and parameter types).

Advanced Type Inference

The Java compiler can even perform more advanced type inference. For instance, the following call is also legal:

String stringElement = "stringElement";
List<Object> objectList = new ArrayList<Object>();

Object theElement = addAndReturn(stringElement, objectList);    

In this case we are using two different types for T : String and Object. The compiler then uses the most specific type argument that makes the method call type correct.

Note, that the most specific type that makes the method call types correct is not necessarily the most specific type used. In the example above, the most specific type used is String, but if the Java compiler infers T to be String, then passing the List<Object> as second parameter to addAndReturn() would result in a compile error. Instead, the compiler infers T to Object, as Object is the most specific type that works in this case, for both the first and second parameter.

The inverse generic type combination is not valid though:

Object objectElement = new Object();
List<String> stringList = new ArrayList<String>();

Object theElement = addAndReturn(objectElement, stringList);

In this case the Java compiler infers, that for the method call to be type safe, the genric type T must be a String. The objectElement passed in for the T element parameter must then also be a String (and it isn't). Therefore the compiler will report an error.

Class Objects as Type Literals

Imagine if you have method that takes a Class object, and is supposed to return an instance of that class. In that case you would like to have the Java compiler infer the return type of the method from the Class object passed to it as parameter. This is actually possible in Java.

Look at this example:

public static <T> T getInstance(Class<T> theClass)
    throws IllegalAccessException, InstantiationException {

    return theClass.newInstance();
}

Notice how the method declares a generic type T for the Class parameter, as well as for the return type of the method. This signals to the Java compiler that the return type of the method should be of the type of the Class object passed in. Thus, if you call with String.class - then T will be inferred to String.

I explain this in more detail in the tutorial Java Generics - Class Objects as Type Literals

Jakob Jenkov

Featured Videos

Java ForkJoinPool

P2P Networks Introduction




















Advertisements

High-Performance
Java Persistence
Close TOC
All Tutorial Trails
All Trails
Table of contents (TOC) for this tutorial trail
Trail TOC
Table of contents (TOC) for this tutorial
Page TOC
Previous tutorial in this tutorial trail
Previous
Next tutorial in this tutorial trail
Next