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
ä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()
Wie leitet die Methode den Typ von
ab?<T>
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:
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 Variablenlist
zu, deren Typ ich nicht angegeben habe?
Hier ist die Quelle von Gson.fromJson(String, Type)
:
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:
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.