wie leitet die Methode den Typ von T ab

8

Die folgende Methode funktioniert einwandfrei

%Vor%

Aber ich habe nicht angegeben, was & lt; T & gt; ist in dieser Methode. Wie weist der Compiler den von der Methode fromJson zurückgegebenen Wert der Variablen list zu, deren Typ ich nicht angegeben habe?

Ich habe gerade die Gültigkeit der Antworten getestet, die angeben, dass <T> aus dem Rückgabetyp der Methode abgeleitet wird. Es scheint nicht zu funktionieren. Bitte überprüfen Sie den folgenden Code. es kompiliert nicht einmal

%Vor%

änderte die Quelle erneut und testete sie und es kam zu einem Kompilierzeitfehler

%Vor%

Sample1.java:13: error: incompatible types T list = getT("test"); ^ required: T found: List where T is a type-variable: T extends Object declared in method test()

    
Thirumalai Parthasarathi 09.03.2014, 08:29
quelle

2 Antworten

9
  

Wie leitet die Methode den Typ von <T>

ab?

Es tut es nicht. Generische Methoden leiten ihre generischen Typen nicht ab - deshalb wird T als -Typ-Parameter bezeichnet. Der -Aufrufer der Methode stellt ein type-Argument für T bereit. Wenn dies der Fall ist, kann basierend auf dem Kontext der Argumente und des Zieltyps des Methodenaufrufs vom Compiler abgeleitet werden.

Zum Beispiel:

%Vor%

emptySet deklariert einen Typparameter T , benötigt keine Argumente und gibt Set<T> zurück. Hier leitet der Compiler T basierend auf dem Zieltyp String auf Set<String> ab.

Ein anderes Beispiel:

%Vor%

singleton deklariert einen Typparameter T , nimmt T und gibt Set<T> zurück. Hier gibt es keinen Zieltyp, aber der Compiler leitet T basierend auf dem Argument String auf "asdf" ein.

Aber generische Inferenz ist nur eine Annehmlichkeit. Ohne sie könnten wir type-Zeugen verwenden, um explizit Typargumente anzugeben:

%Vor%

Dies bringt uns zu Ihrer Methodensignatur:

%Vor%

fromJsonArray deklariert einen Typparameter T , aber gibt nichts zurück, was mit dem Typ T zusammenhängt oder Argumente bezieht, die sich auf T beziehen. Bei einem Aufruf von fromJsonArray hat der Compiler keine Informationen, aus denen T abgeleitet werden kann. Sein type-Argument wird standardmäßig auf die obere Grenze Object gesetzt, es sei denn, ein Typ-Zeuge wird verwendet:

%Vor%

Das ist aber egal, weil <String> keinen Einfluss auf das Verhalten des Methodenaufrufs oder seiner Kompilierung hat. T ist bedeutungslos * und kann entfernt werden aus der Deklaration von fromJsonArray .

  

Wie weist der Compiler den von der Methode fromJson zurückgegebenen Wert der Variablen list zu, deren Typ ich nicht angegeben habe?

Hier ist die Quelle von Gson.fromJson(String, Type) :

%Vor%

Sie können sehen, dass es einen beliebigen Typparameter T deklariert und das deserialisierte Objekt in T umwandelt. Dies wird als ungeprüfter Cast bezeichnet, da er nicht schnell fehlschlägt, wenn er falsch ist. Das liegt daran, dass T zur Laufzeit gelöscht wurde. Sie können sehen, dass der Code eine Warnung darüber unterdrückt, weil es im Allgemeinen eine schlechte Idee ist. Indem nicht eingeschränkt wird, was T auf den Argumenten der Methode basiert, hat der Gson-Code die Kontrolle darüber effektiv an den Aufrufer übergeben. Wenn du geschrieben hast:

%Vor%

aber tToken repräsentiert HashSet<String> , Sie erhalten zur Laufzeit ClassCastException in dieser Zeile. Schlechter, wenn tToken repräsentiert ArrayList<Integer> , würde es nicht einmal in dieser Zeile fehlschlagen, weil die JVM nur ein List sehen würde und die Zuordnung zu passieren. Ein ClassCastException würde irgendwann später geworfen werden, sobald Ihr Code versucht hat, die Integer -Elemente der Liste wie String s zu behandeln (und die Ausnahme wäre beim Debuggen verwirrend).

Um Ihre Frage zu der Aufgabe zu beantworten, können Sie das Ergebnis von fromJson dem Compiler zuweisen. Es liegt an Ihnen, dass es korrekt ist.

Sie fragen sich vielleicht, Warum sollte Gson eine ungeprüfte Besetzung machen und unsicheren Code erlauben? Die Antwort ist, dass es eine Annehmlichkeit ist, die auf Sprachbeschränkungen zurückzuführen ist. Ihre andere Unterschrift ist sicherer:

%Vor%

Aber es gibt keine Möglichkeit, generische Typen mit Class - no List<String>.class zu repräsentieren. Nur ein Type kann dies tun, und es ist nicht selbst generisch. fromJson könnte eine TypeToken<T> benötigt haben, aber es gibt noch andere Möglichkeiten, eine Type zu erhalten, das wäre also restriktiv.

Die Rückkehr von Object und das Erzwingen der unkontrollierten Besetzung durch den Aufrufer wäre transparenter gewesen, aber die Gson-Entwickler wollten diese "Hässlichkeit" wahrscheinlich vermeiden.

    
Paul Bellora 10.03.2014, 00:21
quelle
3
%Vor%

Es wird vom Rückgabetyp von g.fromJson().

abgeleitet     
EJP 09.03.2014 10:41
quelle

Tags und Links