例如,如果我有一个方法
public INode getNode(final int offset);
我假设它没有添加任何东西来使方法返回类型通用,例如:
public <T extends INode> T getNode(final int offset);
还是我错过了什么?我认为只有当参数之一是相同类型(或超/子类型)时,通用返回类型才有价值?
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 必须在它之前)
当然有,叫做访问者模式。
T
在您给出的示例中,除了强制实现的开发人员强制转换返回值(in )之外,它并没有真正增加任何价值。(除非它有办法获得一个T
值,但为此它需要调用另一个返回的方法T
,所以你只是将演员表移动得更远一点。
因此,在您向我们展示的情况下,这并不是一个好主意。
在少数情况下,仅应用于返回值的泛型可能很有用。例如:
public static <T> Collection<T> generateCollection() {
return new ArrayList<T>();
}
这允许您创建一个对象Collection
,T
而无需进行任何强制转换。
或者,如果您希望开发人员执行实现以转换他的对象(主要在所述对象使用泛型时有效),示例来自Collections
:
public static final <T> Set<T> emptySet() {
return (Set<T>) EMPTY_SET;
}
资源: