2012-04-09 136 views
3

如果我有一个方法,例如返回泛型方法

public INode getNode(final int offset); 

我认为它不添加东西,使该方法的返回类型通用的,比如:

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

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

+0

它可能会增加更多的价值,但是,如果在类中定义泛型参数,我会认为它会增加更多的价值。 – Joel 2012-04-09 21:05:37

+0

是什么问题?什么“不加什么东西”意味着什么? – 2012-04-09 21:57:26

回答

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); 
} 

或在科林的答案,其中类型变量仅仅出现类型参数在返回的例子类型,这是由于类型擦除可接受的。

编辑

我觉得有没有类型保存方式,如果一个人想投的确切类型的节点(而不是的instanceof有它前面)

当然有是,它叫visitor pattern

+0

我们坚持节点为INode,即每个节点都必须实现的INode接口。然后我们有一个用于“结构”节点的接口IStructNode。事务游标提供上述方法,例如moveTo(nodeID),而它在内部调用getNode(offset)。另一种方法是getNode(),它将节点作为INode进行传递,将getStructuralNode()作为IStructNode进行传递,或者将其封装在实现空对象模式的“NullNode”中。我认为没有类型保存方式,如果一个人想投到节点的确切类型(而不是instanceof必须先于它) – Johannes 2012-04-09 21:54:05

+0

这是否应该修改您的问题?如果是这样,那么请使用问题的编辑按钮。这也可以让你构造和格式化修正。 – meriton 2012-04-09 22:03:04

+0

是的,当然,访问者模式;-)我已经在大约一年前实现了它,但是没有想到它......好啊。 – Johannes 2012-04-10 05:42:56

1

在您给出的示例中,除了强制实施的开发人员转换返回值(在T中)之外,它并不真正添加任何值。 (除非它有办法获得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; 
} 

资源: