Java泛型和静态工厂方法 - 语法

时间:2013-12-23 22:06:00

标签: java generics syntax static factory

这就是我所拥有的:

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>();
    }
...
}

我的问题实际上只是泛型的语法加上静态工厂方法的语法。我真的不明白为什么我们把&lt; T>在方法声明中返回类型之前。有点像类型转换吗?任何帮助将不胜感激!

5 个答案:

答案 0 :(得分:26)

您要问的是类型推理

因为它是一个静态方法,它必须从某个地方推断出通用类型;您没有该类的实例。这就是<T>的含义。

如果你的方法没有参数,它实际上是从赋值的目标推断它。例如,假设您的方法如下所示:

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

使用此方法时,会从目标推断T(在本例中为String):

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

在你有一个Generic参数的另一个静态方法中,从传入的类型中推断出T

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

在这里,如果您尝试过:

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

它会告诉您目标类型错误,并且需要List<Integer>

具体而言,这将在JLS的15.12.2.715.12.2.8部分中介绍。

答案 1 :(得分:8)

你必须用这样的糖装饰静态方法的原因是,作为一个静态方法,它不会从类的声明中继承T

您也可以这样做:

// 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);
}

声明的简单叙述可能会有所帮助:

// 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>();
}

答案 2 :(得分:5)

这是参数化静态方法的唯一方法,因为Node声明中的原始T绑定到Node的实例字段和方法。所以你可以写:

public static <T1> Node<T1> newNode(){
    return new Node<T1>();
}

原始T绑定到Node类的实例,无法在静态上下文中引用。这将导致编译错误:

// ERROR
public static Node<T> newNode(){
    return new Node<T>();
}

答案 3 :(得分:4)

<T>只是信号,此方法使用T作为类型变量。如果没有它,编译器会认为,Tclassinterfaceenum在某处声明并输出错误。它与您的第一行中使用的T不同。您可以将此方法中的T替换为任何其他字母,这可能有助于理解。

答案 4 :(得分:0)

T从参数

推断出来
public static <T> List<T> getNewListWithElement(T element)

编译器如何区分T作为类和T作为泛型参数?解决方案是使用指定T元素是通用的而不是类/接口。

从使用情况推断

public static <T1> Node<T1> newNode(){
    return new Node<T1>();
}

如果没有声明,谁将成为方法体内的T1?