如果我有方法,例如
public INode getNode(final int offset);
我认为它没有添加一些东西来使方法返回类型通用,例如:
public <T extends INode> T getNode(final int offset);
或者我错过了什么?我认为泛型返回类型只有在其中一个参数属于同一类型(或超级/子类型)时才有价值?
答案 0 :(得分:4)
public <T extends INode> T getNode(final int offset);
这不仅不会向调用者提供任何其他信息,而且完全是危险的:实现该方法签名的唯一方法是使用未经检查的强制转换,它不能是类型安全的,因为方法的类型参数由其调用者指定(显式或隐含地通过类型推断),并且类型参数不可用于此方法的实现。例如,请考虑以下程序:
class NodeCollection {
private INode[] nodes = new INode[42];
public <T extends INode> T getNode(final int offset) {
return (T) nodes[offset];
}
public <T extends INode> setNode(final int offset, T node) {
nodes[offset] = node;
}
}
class ANode implements INode {}
class BNode implements INode {
void foo();
}
public class Test {
public static void main(String[] args) {
NodeCollection nc = new NodeCollection();
nc.setNode(0,new ANode());
BNode b = nc.getNode(0); // throws ClassCastException (sic!)
}
}
最佳做法:不要使用未经检查的强制转换,除非您确实确定它在运行时的类型是正确的。
我认为泛型返回类型只有在其中一个参数属于同一类型(或超级/子类型)时才有价值?
还有更多案例,例如:
public <T> T getFavorite(Class<T> clazz) {
return clazz.cast(favorites.get(clazz));
}
或
interface List<E> {
E get(int index);
}
或Colin的答案中的示例,其中类型变量仅在返回类型中显示为作为类型参数,由于类型擦除,这是可接受的。
修改强>:
我认为如果想要转换为确切的节点类型(而不是instanceof必须在它之前),则没有类型保存方式
当然有,它被称为visitor pattern。
答案 1 :(得分:1)
在您给出的示例中,除了强制实现的开发人员强制转换返回值(在T
中)之外,它并没有真正添加任何值。 (除非它有办法获得T
值,但为此需要调用另一个返回T
的方法,所以你只需要进一步移动演员。
在你向我们展示的情况下,这不是一个好主意。
在少数情况下,仅应用于返回值的泛型可能很有用。例如:
public static <T> Collection<T> generateCollection() {
return new ArrayList<T>();
}
这允许您创建Collection
的{{1}}对象而无需进行任何演员。
或者,如果您希望开发人员执行实现来投射他的对象(主要是在所述对象使用泛型时工作),例如来自T
:
Collections
<强>资源:强>