返回类型的泛型方法

时间:2012-04-09 21:02:50

标签: java generics

如果我有方法,例如

public INode getNode(final int offset);

我认为它没有添加一些东西来使方法返回类型通用,例如:

public <T extends INode> T getNode(final int offset);

或者我错过了什么?我认为泛型返回类型只有在其中一个参数属于同一类型(或超级/子类型)时才有价值?

2 个答案:

答案 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

<强>资源: