wake-up-neo.net

Was bedeutet der generische Charakter der Klasse Klasse <T>? Was ist T?

Ich verstehe Generika, wenn es um Sammlungen geht. Was bedeutet es jedoch im Fall der Klasse Class<T>? Wenn Sie ein Class-Objekt instanziieren, gibt es nur ein Objekt. Warum also der T-Parameter? Was spezifiziert es? Und warum ist es notwendig (falls ja)?

37
Tim

Der Parameter <T> wurde zu Java.lang.Class hinzugefügt, um ein bestimmtes Idiom zu aktivieren1 - Verwendung von Class Objekten als typsichere Objektfabriken. Mit dem Zusatz von <T> können Sie Klassen typensicher wie folgt instanziieren:

T instance = myClass.newInstance();

Der Typparameter <T> steht für die Klasse selbst. So können Sie unangenehme Auswirkungen der Typenlöschung vermeiden, indem Sie Class<T> in einer generischen Klasse speichern oder als Parameter an eine generische Methode übergeben. Beachten Sie, dass T alleine nicht ausreicht, um diese Aufgabe auszuführen2: Der Typ von T wird gelöscht, sodass er unter der Haube Java.lang.Object wird.

Hier ist ein klassisches Beispiel, bei dem der <T>-Parameter der Klasse wichtig wird. Im folgenden Beispiel kann der Java-Compiler die Typsicherheit gewährleisten, indem Sie eine typisierte Auflistung aus einem SQL-String und einer Instanz von Class<T> erstellen lassen. Beachten Sie, dass die Klasse als factory verwendet wird und deren Typensicherheit zur Kompilierzeit überprüft werden kann:

public static <T> Collection<T> select(Class<T> c, String sqlStatement) {
    Collection<T> result = new ArrayList<T>();
    /* run sql query using jdbc */
    for ( /* iterate over jdbc results */ ) {
        T item = c.newInstance();
        /* use reflection and set all of item’s fields from sql results */
        result.add(item);
    }
    return result;
}

Da Java den Typparameter löscht und ihn zu einem Java.lang.Object oder einer Klasse macht, die als obere Begrenzung des Generikums angegeben ist, ist es wichtig, auf das Class<T>-Objekt in der select-Methode zuzugreifen. Da newInstance ein Objekt vom Typ <T> zurückgibt, kann der Compiler eine Typprüfung durchführen und eine Umwandlung beseitigen.


1Sonne Oracle hat ein guter Artikel, der dies alles erklärt veröffentlicht.
2 Dies unterscheidet sich von Implementierungen von Generics ohne Löschen von Typen, z. B. in .NET.
3 Java Generics-Tutorial von Oracle.

47
dasblinkenlight

Die answer von dasblinkenlight demonstrierte bereits eine der Hauptanwendungen dieses Parameters. Es gibt einen weiteren Aspekt, den ich für relevant halte: Wenn Sie diesen Parameter verwenden, können Sie die Art der Klasse einschränken, die Sie an einem bestimmten Ort übergeben möchten. So z.

Class<? extends Number> cls

bedeutet, dass cls eine beliebige Klasse sein kann, die die Number-Schnittstelle implementiert. Dies kann dazu beitragen, bestimmte Fehler beim Kompilieren abzufangen, und Anforderungen an Klassenargumente werden deutlicher.

Vielleicht ist ein Vergleich zum Fall ohne Generika in Ordnung

// Java ≥5 with generics    // Java <5 style without generics
Class<? extends Foo> c;     Class c;
Foo t1 = c.newInstance();   Foo t1 = (Foo)c.newInstance();
Object obj;                 Object obj;
Foo t2 = c.cast(obj);       Foo t2 = (Foo)c.cast(obj);

Wie Sie sehen können, wäre es nicht erforderlich, T als Argument zu verwenden, da die entsprechenden Methoden Object anstelle von T zurückgeben müssen. Wenn Foo selbst ein generisches Typargument ist, werden alle diese Casts nicht markiert, was zu einer Folge von Compiler-Warnungen führt. Sie können sie unterdrücken, das Kernproblem bleibt jedoch bestehen: Der Compiler kann die Gültigkeit dieser Umwandlungen nur überprüfen, wenn Sie das Typargument ordnungsgemäß verwenden.

8
MvG

In Java gibt es eine einzige Metaklasse: Class. Seine Instanzen (es gibt nur eine pro Typ) werden zur Darstellung von Klassen und Interfaces verwendet. Daher bezieht sich T in Class<T> auf das type der Klasse oder des Interfaces, das die aktuelle Instanz von Class darstellt.

1
Óscar López

Die Verwendung von Generika im Class-Typ bestimmt den Klassentyp. Wenn ich 'Class obj' habe, kann mein Objekt obj nur Kinder von Charsequence enthalten. Dies ist ein optionales Argument. Ich werde oft ein "?" um Warnungen vom Eclipse IDE zu vermeiden, wenn ich keinen bestimmten Klassentyp benötige.

0
Eldius