Reputation: 928
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!
Upvotes: 30
Views: 21670
Reputation: 21499
T inferred from parameter
public static <T> List<T> getNewListWithElement(T element)
How can the compiler make the difference between T as a class and T as a generic argument? The solution is to use to specify T element is a generic and not a class/interface.
T inferred from usage
public static <T1> Node<T1> newNode(){
return new Node<T1>();
}
Who will be T1 inside the method body if no declaration would be made?
Upvotes: 0
Reputation: 76908
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.
Upvotes: 36
Reputation: 65859
The reason you must decorate the static method with such sugar is because, as a static method, it does not inherit the T
from the declaration of the class.
You could just as well do:
// static factory methods
public static <Q> Node<Q> newNode(){
return new Node<Q>();
}
public static Node<String> newStringNode(String s){
return new Node<String>(s);
}
A simple narrative to the declaration may assist:
// This static method would have a <T> parameter to the class if it was not static
public static <T>
// It returns an object of type `Node` with generic parameter T
Node<T> newNode(){
// And here it is doing it's business.
return new Node<T>();
}
Upvotes: 9
Reputation: 16516
This is an only way to parametrize a static method, as the original T
in the Node declaration is bound to instance fields and methods of the Node. So you could write:
public static <T1> Node<T1> newNode(){
return new Node<T1>();
}
The original T
is bound to an instance of Node
class and cannot be referenced in static context. This would result in a compilation error:
// ERROR
public static Node<T> newNode(){
return new Node<T>();
}
Upvotes: 6
Reputation: 3914
The <T>
is just the signal, that this method uses T
as type variable. Without it, the compiler would think, T
is a class
, interface
or enum
that is declared somewhere and output an error. It is not the same T
as used in your first line. You can replace the T
in this method with any other letter, maybe that helps understanding.
Upvotes: 4