2013-02-12 7 views
7

ich ein Problem mit dem Verständnis solcher generischen Methodenaufruf haben:Allgemeine Methodenaufruf mit <T>

object = ObjectGenerator.<T> getObject(objectName); 

kommt hier einen Kontext für oben beschriebene Situation:

class GenClass<T> { 

    private T object; 

    // ... some code 

    public void initObject(String objectName) { 
     object = ObjectGenerator.<T> getObject(objectName); 
    } 
} 

class ObjectGenerator { 

    public static <T extends Object> T getObject(String name) { 
     // some code 
     return someObject; 
    } 
} 

Die Frage ist, welche Rolle spielt <T> vor getObject(objectName) Aufruf?

+1

+1 für ich habe das vorher nicht gesehen. –

+0

Ich frage nicht nach Sinn, sondern nur etwa eine Zeile Code. Ich kann die Methodensignatur in ' T getObject (String name, Klasse clazz)' ändern - es spielt keine Rolle. Nur diese eine Zeile mit Aufruf dieser Methode mit '' ist für mich verwirrend – emka86

Antwort

7

Hinweis: In dem spezifischen Beispiel, das Sie angegeben haben, sollte ObjectGenerator.getObject(objectName); kompiliert werden.

In einigen Situationen kann der Typ-Inferenz-Mechanismus nicht die Tatsache beheben, dass in:

T object; 
object = ObjectGenerator.getObject(objectName); 

der zurückgegebene Typ T sein sollte. In diesem Fall müssen Sie dem Compiler eine kleine Hilfestellung geben, indem Sie explizit den von Ihnen erwarteten Rückgabetyp angeben. Hier

ist ein konstruiertes Beispiel, wo Sie brauchen, um explizit den generischen Typ angeben:

class Example { 
    public static <T> List<T> m1() { 
     return m2(Arrays.<T> asList()); //Arrays.asList() would not compile 
    } 
    public static <T> List<T> m2(List<T> l) { 
     return l; 
    } 
} 
+0

Unter welchen Situationen würde der "Inferenzmechanismus" nicht in der Lage sein zu wissen, was der zurückgegebene Typ sein sollte? – asteri

+0

@Jeff Ich habe ein Beispiel hinzugefügt - die genauen Situationen, in denen dies passiert, hängt vom Ergebnis der Anwendung der [Inferenzregeln] ab (http://docs.oracle.com/javase/specs/jls/se7/html/jls- 15.html # jls-15.12.2.7), die etwa 12 Seiten lang in der pdf-Version der JLS sind, also nicht ganz sicher, um ehrlich zu sein. Am Ende sehe ich es so: Entweder kompiliert es ohne den expliziten Typ und ich bin glücklich oder nicht und ich füge es einfach hinzu ... – assylias

+0

Ja, ich habe es! Das ist eine sehr gute Erklärung für mich und wenn ich mir diese Spezifikation von deinem Link ansehe, denke ich, dass es viel mehr fiese Situationen zu entdecken gibt! :) – emka86

0

object kann Kind von T. sein

Natürlich getObject sollte besser definiert wurden:

public static <T> T getObject(Class<T> objectClass, String name) { 
    return objectClass.getConstructor(String.class).newInstance(name); 
    //return objectClass.getConstructor().newInstance(); 
} 

sonst gibt es keine Art sichere Konstruktion möglich, weil der so genannten Typ Löschung.

-1
object = ObjectGenerator.getObject(objectName); 

immer wieder Objekt des Objekts, da Sie eine statische Methode aufrufen. Für explizit die allgemeine Aufgabe bekommen haben Sie für T, in Ihrem Code verwendet,

object = ObjectGenerator.<T> getObject(objectName); 

<T> in statischen Kontext verwendet wird. Für nicht statischen Aufruf ist es nicht erforderlich.

+0

-1 Statischer Kontext hat nichts damit zu tun, dass explizit Typargumente angegeben werden. –

+0

danke für die Erleuchtung mich :) – prasanth

0

Ich fand etwas hier: https://stackoverflow.com/a/338906/443427 es kann Ihnen helfen.

Von dem, was ich die allgemeine darstellen lesen kann, dass Compiler verwenden muss, den neu abgestimmt Werttyp zu berechnen, die allgemeine passieren vorwärts

als Notiz dies auch gut funktionieren (siehe in ObjectGenerator unterscheidet sich von T):

public class ObjectGenerator<X> { 
    public static <T extends Object> Set<T> getObject(String name) { 
    // some code 
    return null; 
    } 
} 
0

ich nicht völlig mit der akzeptierte Antwort zustimmen, in dem es heißt:

in einem solchen Fall, können Sie den Compiler ein wenig Hilfe von explizitgeben müssenzeigt den Rückgabetyp an, den Sie erwarten.

Das klingt nicht richtig für mich. Wenn ich die generische Methode und die Typinferenz verstehe, gibt der in eckigen Klammern angegebene Typ nicht direkt den Rückgabetyp der generischen Methode an. Stattdessen könnte der Typ T Rückgabetyp, Argumenttyp, lokaler Variablentyp sein, der der generischen Methode zugeordnet ist.

Eigentlich müssen wir dank Typ-Inferenz-Mechanismus in den meisten Fällen den Typ-Parameter T nicht angeben (nicht nur in einigen Situationen). In Ihrem Beispiel kann die <T> wie in den meisten anderen Fällen vom Methodenaufruf ObjectGenerator.<T> getObject(objectName) ausgeschlossen werden. Dies liegt daran, dass der Typ T des generischen Verfahrens leicht aus dem Typ, dem das Ergebnis zugewiesen wird, oder zurückgegeben werden kann. Mit anderen Worten, da Sie vor dem Methodenaufruf private T object deklarieren, wird der Typ T erfolgreich als T gefolgert.

Mein Anspruch kann durch die folgende Aussage von a definitive tutorial gesichert werden:

Typ-Inferenz ist ein Java-Compiler in der Lage ist, zu betrachten jede Methode Aufruf und eine entsprechende Erklärung des Typs Argument (oder Argumente) zu bestimmen das macht den Aufruf anwendbar. Der Inferenzalgorithmus bestimmt die Typen der Argumente und, falls verfügbar ist, den Typ, dem das Ergebnis zugewiesen oder zurückgegeben wird. Schließlich versucht der Inferenzalgorithmus den spezifischsten Typ zu finden, der mit allen Argumenten funktioniert.

Zwei Beispiele darüber, wie die Inferenz funktioniert:

static <T> T pick(T a1, T a2) { return a2; } 
Serializable s = pick("d", new ArrayList<String>()); 

Der Typ T als Serializable basierend auf dem ausgewiesenen Zessionar Typ abgeleitet.

public static <U> void addBox(U u, java.util.List<Box<U>> boxes) {} 
BoxDemo.<Integer>addBox(Integer.valueOf(10), listOfIntegerBoxes); 

Der Typ U als Integer basierend auf dem Typ des übergebenen Argument abgeleitet wird (d.h. Integer.valueOf(10) ist vom Typ Integer). Daher kann <Integer> in dem obigen Methodenaufruf sicher weggelassen werden.

Zusammenfassend können wir, ohne den Typparameter der generischen Methode aus dem Argumenttyp oder dem Typ, dem das Ergebnis zugewiesen oder zurückgegeben wird (beim Aufruf der Methode), die Typspezifikation sicher weglassen direkt vor dem Methodenaufruf.