Java Generics and Static Factory Methods -- Syntax

FateNuller picture FateNuller · Dec 23, 2013 · Viewed 16.8k times · Source

Here's what I've got:

public class Node<T> {

    // instance variables
    private Node<T> next;
    private T data;

    // construct with data
    private Node(T data){
        next = null;
        this.data = data;
    }

    // construct without data
    private Node(){
        next = null;
        this.data = null;
    }

    // static factory method
    public static <T> Node<T> newNodeWithData(T data){
        return new Node<T>(data);
    }

    // static factory method
    public static <T> Node<T> newNode(){
        return new Node<T>();
    }
...
}

My question really just about the syntax of generics coupled with that of a static factory method. I don't really understand why we put the < T > before the return type in the method declaration. Is it kind of like typecasting? Any help would be much appreciated!

Answer

Brian Roach picture Brian Roach · Dec 24, 2013

What you're asking about is type inferrence.

Since it's a static method it has to infer the Generic type from somewhere; You don't have an instance of the class. That's what the <T> means.

In the case of your method that takes no arguments it's actually inferring it from the target of the assignment. For example, say your method looked like this:

public static <T> List<T> getNewList() {
    return new ArrayList<T>();
}

When using this method, T is inferred from the target (in this case String):

List<String> myList = MyClass.getNewList();

In your other static method where you have a Generic argument, T is being inferred from the type being passed in:

public static <T> List<T> getNewListWithElement(T element) {
    List<T> list = new ArrayList<T>();
    list.add(element);
    return list;
}

Here, if you tried doing:

List<String> myList = MyClass.getNewListWithElement(new Integer(4));

It would tell you that your target type was wrong, and you needed a List<Integer>

Specifically this is covered in sections 15.12.2.7 and 15.12.2.8 of the JLS.