2012-04-09 131 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; 
} 

資源: