2015-11-12 3 views
5

Vorwort:Ich verstehe Generika und wie sie auf der Klassenebene (z class MyClass<T>) erklärt, aber ich habe es nie auf der Ebene einer statischen Methode deklariert gesehen, und ohne explizite Bindungen (z class MySubclass<String> extends MyClass).Was ist eine generische Methode und wie ist <T> in diesem Fall gebunden?

Ich habe dieses Code-Snippet in einer App gefunden, an der ich gerade arbeite (diesen Teil habe ich nicht geschrieben). Ich habe noch nie eine so erklärte Methode gesehen. <T> ist nicht irgendwo anders in der Klasse definiert. Intent.getExtras().get() gibt eine Object zurück, die tatsächlich eine String, ... usw. sein kann.

private static <T> T getItemExtra(final Intent intent, final String extraName) { 
    T item = null; 

    if(intent != null && intent.getExtras() != null) { 
     item = (T) intent.getExtras().get(extraName); 
    } 

    return item; 
} 

Verwendungsbeispiel:

String s1 = getItemExtra(someIntent, "some_string_extra"); 
Uri u1 = getItemExtra(someIntent, "some_uri_extra"); 

Wie funktioniert die JVM wissen, welche Art für <T> zu benutzen? (Ja, diese Methode wird kompiliert und erfolgreich ausgeführt).

+3

Nicht entfernt ein Dup der anderen Frage. –

+0

@Nilish Ich frage nach generischen Methoden, nicht nach generischen Klassen. Ich habe die Frage aktualisiert, um dies zu berücksichtigen. –

+0

@ OliverGondža Ja ich muss zugeben, das ist ein Duplikat. –

Antwort

1

Das ist, was in Java als generic method bekannt ist. Das T in stellt einen Typ dar, den Sie normalerweise angeben würden. Der Compiler würde dann alle Instanzen von T durch den Typ ersetzen, mit dem Sie ihn ersetzt haben. Wenn Sie dies nicht tun, versucht der Compiler, aus den verfügbaren Informationen auf den richtigen Typ zu schließen.

Sie sollten durch das Java Generics Tutorial für eine eingehendere Erklärung suchen.

1

T ist, was als eine Art Schnittstelle bekannt ist. In diesem Fall ist der Rückgabetyp eine Typschnittstelle, sodass einfach gesagt wird, dass String oder Uri zurückgibt, damit der Compiler weiß, dass diese Methode das Objekt zurückgibt. Nichtsdestoweniger ist dies nicht das beste Beispiel für die Eingabe von Schnittstellen, daher ist hier ein einfacheres Beispiel.

ArrayList implementiert eine Art Schnittstelle, außer Sie die Arraylist sagen, welche Objekttyp es enthält, mit der Ausnahme statt T sie E verwenden, was in Ordnung ist, weil der Charakter beliebig ist, solange Sie während das gleiche Zeichen verwenden Ihre Implementierung.

Hier ist ein relevanter Ausschnitt aus der aktuellen implementation:

public class ArrayList<E> extends AbstractList<E> 
     implements List<E>, RandomAccess, Cloneable, java.io.Serializable 
{ 

Also, wenn Sie ArrayList<String> erklären der Compiler E mit String bei der Kompilierung ersetzen wird. Gleiches gilt für ArrayList<YourCustomObject> es wird E mit YourCustomObject während der gesamten Implementierung ersetzen.

+0

Meine Frage bezieht sich auf generische Methoden, nicht auf generische Klassen. –

+0

Es ist die gleiche Sache, eine, die Sie im Konstruktor angeben, die andere, die Sie angeben, wenn Sie die Methode aufrufen. – CodyEngel

3

Woher weiß die JVM welchen Typ für <T> zu verwenden?

Die grundlegende Antwort ist, tut es nicht. In Java werden generische Typen vom Typüberprüfer zum Zeitpunkt der Kompilierung verwendet, aber sie werden aus dem Programm entfernt, wenn das Programm tatsächlich ausgeführt wird. So zum Beispiel, die Besetzung zu T in item = (T) intent.getExtras().get(extraName) tut eigentlich nichts zur Laufzeit: es ist effektiv eine Besetzung zu Object, immer, unabhängig davon, welchen Typ der Anrufer erwartet T zu sein.(Dies unterscheidet sich von einem Cast zu einem normalen Typ wie String, wo das Programm mit einer Ausnahme sofort fehlschlägt, wenn Sie versuchen, das falsche Ding zu werfen.)

Die Tatsache, dass Sie auf T ohne einen Scheck umwandeln können, ist ein Lücke in Javas Typsystem, die seltsame Klassenausnahmen verursachen kann. Zum Beispiel, wenn Sie

String s = getItemExtra(...); 
s.toLowerCase(); 

sagen, aber getItemExtra nicht einen String zurück, dann werden Sie eine Ausnahme in der zweiten Zeile erhalten Sie sagen, dass s kein String ist, auch wenn es keine Besetzung auf, dass Linie. Wenn der Java-Compiler eine Umwandlung nach T sieht, wird daher eine Warnmeldung generiert, die besagt, dass er nicht überprüfen kann, ob Ihre Typumwandlung zulässig war und dass es zu Problemen wie dieser kommen könnte.

+1

Tatsächlich erhalten Sie eine Ausnahme in der ersten Zeile, weil die erste Zeile "String s = (String) getItemExtra (...);" wird. –

Verwandte Themen