Java 泛型和静态工厂方法——语法
Posted
技术标签:
【中文标题】Java 泛型和静态工厂方法——语法【英文标题】:Java Generics and Static Factory Methods -- Syntax 【发布时间】:2014-01-12 03:55:30 【问题描述】:这是我得到的:
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>();
...
我的问题实际上只是关于泛型的语法以及静态工厂方法的语法。我不太明白为什么我们在方法声明中将
【问题讨论】:
【参考方案1】:您要问的是类型推断。
由于它是一个静态方法,它必须从某个地方推断出 Generic 类型;您没有该类的实例。这就是<T>
的含义。
在你的方法不带参数的情况下,它实际上是从赋值的目标中推断出来的。例如,假设您的方法如下所示:
public static <T> List<T> getNewList()
return new ArrayList<T>();
使用此方法时,T
是从目标推断出来的(在本例中为 String
):
List<String> myList = MyClass.getNewList();
在您具有通用参数的其他静态方法中,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.7 和 15.12.2.8 部分特别介绍了这一点。
【讨论】:
【参考方案2】:你必须用这种糖装饰静态方法的原因是,作为一个静态方法,它没有从类的声明中继承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>();
【讨论】:
【参考方案3】:这是对静态方法进行参数化的唯一方法,因为 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>();
【讨论】:
【参考方案4】:<T>
只是一个信号,这个方法使用T
作为类型变量。没有它,编译器会认为T
是class
、interface
或enum
,它在某处声明并输出错误。它与第一行中使用的 T
不同。你可以把这个方法中的T
换成其他字母,或许有助于理解。
【讨论】:
【参考方案5】:从参数推断出的T
public static <T> List<T> getNewListWithElement(T element)
编译器如何区分 T 作为类和 T 作为泛型参数?解决方案是使用指定 T 元素是泛型而不是类/接口。
T 从使用情况推断
public static <T1> Node<T1> newNode()
return new Node<T1>();
如果不做声明,方法体内的T1是谁?
【讨论】:
以上是关于Java 泛型和静态工厂方法——语法的主要内容,如果未能解决你的问题,请参考以下文章
Effective Java大厂实战之考虑以静态工厂方法代替构造方法