3

例如,如果我有一个方法

public INode getNode(final int offset);

我假设它没有添加任何东西来使方法返回类型通用,例如:

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

还是我错过了什么?我认为只有当参数之一是相同类型(或超/子类型)时,通用返回类型才有价值?

4

2 回答 2

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 必须在它之前)

当然有,叫做访问者模式

于 2012-04-09T21:43:48.427 回答
1

T在您给出的示例中,除了强制实现的开发人员强制转换返回值(in )之外,它并没有真正增加任何价值。(除非它有办法获得一个T值,但为此它需要调用另一个返回的方法T,所以你只是将演员表移动得更远一点。

因此,在您向我们展示的情况下,这并不是一个好主意。


在少数情况下,仅应用于返回值的泛型可能很有用。例如:

public static <T> Collection<T> generateCollection() {
    return new ArrayList<T>();
}

这允许您创建一个对象CollectionT而无需进行任何强制转换。

或者,如果您希望开发人员执行实现以转换他的对象(主要在所述对象使用泛型时有效),示例来自Collections

public static final <T> Set<T> emptySet() {
    return (Set<T>) EMPTY_SET;
}

资源:

于 2012-04-09T21:31:16.950 回答