web-dev-qa-db-fra.com

Que signifie la nature générique de la classe? Classe <T>? Ce est t?

Je comprends les génériques en matière de collections. Mais qu'est-ce que cela signifie dans le cas de la classe Class<T>? Lorsque vous instanciez un objet Class, il n'y a qu'un seul objet. Alors pourquoi le paramètre T? Que spécifie-t-il? Et pourquoi est-ce nécessaire (si c'est le cas)?

37
Tim

Le paramètre de type <T> a été ajouté à Java.lang.Class pour activer un idiome spécifique1 - utilisation d'objets Class en tant que fabriques d'objets de type sécurisé. L'ajout de <T> permet essentiellement d'instancier les classes de manière sécurisée, comme ceci:

T instance = myClass.newInstance();

Le paramètre de type <T> représente la classe elle-même, ce qui vous permet d'éviter les effets désagréables de l'effacement du type en stockant Class<T> dans une classe générique ou en le transmettant en tant que paramètre à une méthode générique. Notez que T ne serait pas suffisant en soi pour effectuer cette tâche.2: le type de T est effacé, il devient donc Java.lang.Object sous le capot.

Voici un exemple classique où le paramètre <T> de la classe devient important. Dans l'exemple ci-dessous, le compilateur Java est capable de garantir la sécurité des types en vous permettant de générer une collection typée à partir d'une chaîne SQL et d'une instance de Class<T>. Notez que la classe est utilisée en tant que factory et que son type de sécurité peut être vérifié lors de la compilation:

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;
}

Etant donné que Java efface le paramètre type, ce qui en fait un Java.lang.Object ou une classe spécifiée en tant que borne supérieure du générique, il est important d'avoir accès à l'objet Class<T> dans la méthode select. Étant donné que newInstance renvoie un objet de type <T>, le compilateur peut effectuer une vérification de type en éliminant une conversion.


1Soleil Oracle a publié un bon article expliquant tout cela .
2 Cela diffère des implémentations de génériques sans effacement de type, comme celle en .NET.
3 Tutoriel Java Generics par Oracle.

47
dasblinkenlight

Le answer de dasblinkenlight a déjà démontré l’une des utilisations principales de ce paramètre. Il y a un autre aspect que je considère pertinent: en utilisant ce paramètre, vous pouvez restreindre le type de classe que vous souhaitez transmettre à un emplacement donné. Donc, par exemple.

Class<? extends Number> cls

cela signifie que cls peut être toute classe implémentant l'interface Number. Cela peut aider à détecter certaines erreurs lors de la compilation et à rendre plus explicites les exigences des arguments de classe.

Peut-être une comparaison avec le cas sans génériques est en ordre

// 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);

Comme vous pouvez le constater, ne pas avoir comme argument T nécessiterait un certain nombre d'incantations explicites, car les méthodes correspondantes devraient renvoyer Object au lieu de T. Si Foo est lui-même un argument de type générique, alors tous ces lancements seront décochés, ce qui entraînera une séquence d'avertissements du compilateur. Vous pouvez les supprimer, mais le problème principal demeure: le compilateur ne peut pas vérifier la validité de ces conversions à moins que vous n'utilisiez correctement l'argument de type.

8
MvG

En Java, il existe une seule métaclasse: Class. Ses instances (une seule par type existe) sont utilisées pour représenter les classes et les interfaces. Par conséquent, T dans Class<T> fait référence au type de la classe ou de l'interface que représente l'instance actuelle de Class.

1
Óscar López

L'utilisation de génériques dans le type de classe est top pour définir le type de classe. Si j'ai 'Class obj', mon objet obj ne peut contenir que des enfants de Charsequence ..__ Ceci est un argument optionnel Je mets souvent un '?' pour éviter les avertissements d'Eclipse IDE si je n'ai pas besoin d'un type spécifique de classe.

0
Eldius