2012-04-09 13 views
3

Wenn ich eine Methode, zum BeispielArt von generischen Methoden geben

public INode getNode(final int offset); 

Ich nehme an, es nicht etwas, fügt die Methode Rückgabetyp generisch, zum Beispiel zu machen:

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

Or Habe ich etwas verpasst? Ich denke, generische Rückgabetypen sind nur dann von Wert, wenn einer der Parameter vom selben Typ ist (oder ein Super-/Subtyp)?

+0

Es ist möglich, dass es mehr Wert hinzufügt, aber ich würde denken, dass es noch mehr Wert hinzufügen würde, wenn der generische Parameter in der Klasse definiert wäre. – Joel

+0

Was ist die Frage? Was "fügt nichts hinzu" bedeutet? –

Antwort

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

Nicht nur, dass dies nicht mit dem Anrufer keine zusätzliche Informationen liefern, sondern ist geradezu gefährlich: Die einzige Möglichkeit, diese Methode Unterschrift zu implementieren, ist einen ungeprüft Guss, zu verwenden, die nicht sicher Typ sein , weil die Typparameter einer Methode von ihrem Aufrufer angegeben werden (explizit oder implizit durch Typinferenz) und die Typparameter für die Implementierung dieser Methode nicht verfügbar sind. Betrachten wir zum Beispiel das folgende Programm:

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

Best Practice: Verwenden Sie einen ungeprüften Guss nicht verwenden, es sei denn, Sie wirklich sicher sind, wird es richtig Typ zur Laufzeit sein.

Ich denke, generische Rückgabetypen sind nur von Wert, wenn einer der Parameter vom gleichen Typ (oder ein Super/Subtyp) ist?

Es gibt weitere Fälle, zum Beispiel:

public <T> T getFavorite(Class<T> clazz) { 
    return clazz.cast(favorites.get(clazz)); 
} 

oder

interface List<E> { 
    E get(int index); 
} 

oder die Beispiele in Colins Antwort, wobei die Variable vom Typ erscheint nur als Typ-Parameter im Rück Typ, der aufgrund von Typ löschen akzeptabel ist.

bearbeiten:

Ich denke, es gibt keine Art Art und Weise speichern, wenn man will, auf die genaue Art des Knotens werfen (statt instanceof muss es vorangehen)

Natürlich gibt ist, heißt es visitor pattern.

+0

Wir halten Knoten als INodes fest, das heißt von der Schnittstelle INode, da jeder Knoten es implementieren muss. Dann haben wir eine Schnittstelle IStructNode für "strukturelle" Knoten. Ein Transaktionscursor stellt die obige Methode zur Verfügung, beispielsweise moveTo (nodeID), während intern getNode (offset) aufgerufen wird. Eine andere Methode ist getNode(), die Knoten als INodes liefert und getSurcturalNode() als IStructNode oder in einen "NullNode" verpackt, der das Null-Objektmuster implementiert. Ich denke, es gibt keine Art und Weise zu speichern, wenn man auf den genauen Typ von Knoten werfen will (anstelle von instanceof) – Johannes

+0

Sollte dies Ihre Frage ändern? Wenn ja, dann benutze bitte den Bearbeitungsbutton der Frage. Das würde Ihnen auch ermöglichen, die Änderung zu strukturieren und zu formatieren. – meriton

+0

Ja, sicher, das Besuchermuster ;-) Ich habe es vor ungefähr einem Jahr implementiert, aber ich habe einfach nicht darüber nachgedacht ... ach gut. – Johannes

1

In dem von Ihnen angegebenen Beispiel fügt es keinen Wert hinzu, außer dass der Entwickler der Implementierung gezwungen wird, den Rückgabewert (in T) zu konvertieren. (Es sei denn, es gibt eine Möglichkeit, einen T Wert zu erhalten, aber dafür müsste es eine andere Methode aufrufen, die T zurückgibt, also verschieben Sie die Besetzung nur ein bisschen weiter.

Also nicht wirklich eine gute Idee in der Sollten Sie uns zeigen


Es gibt einige Fälle, in denen die allgemeinen nur auf den Rückgabewert angewandt kann nützlich sein. zum Beispiel:.

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

Dies Sie ein Objekt erstellen kann Collection von T ohne zu werfen.

Oder wenn Sie wollen die Entwickler die Implementierung macht seine Aufgabe zu werfen (meistens funktioniert, wenn das genannte Objekt verwendet Generika), beispielsweise aus Collections:

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

Ressourcen:

Verwandte Themen