Question

Depuis que les génériques ont été introduits, la classe est paramétrée, de sorte que List.class produit la classe < List > ;. C’est clair.

Ce que je ne sais pas, c'est comment obtenir une instance de classe de type paramétrée elle-même, c'est-à-dire classe < liste < chaîne > > . Comme dans cet extrait:

public class GenTest {
    static <T> T instantiate(Class<T> clazz) throws Exception {
        return clazz.newInstance();
    }
    public static void main(String[] args) throws Exception {
        // Is there a way to avoid waring on the line below
        // without using  @SuppressWarnings("unchecked")?
        // ArrayList.class is Class<ArrayList>, but I would like to
        // pass in Class<ArrayList<String>>
        ArrayList<String> l = GenTest.instantiate(ArrayList.class);
    }
}

Je rencontre souvent des variantes de ce problème et je ne sais toujours pas si quelque chose me manque ou s'il n'y a vraiment pas de meilleure façon. Merci pour vos suggestions.

Était-ce utile?

La solution

La classe Class est une représentation d'exécution d'un type. Etant donné que les types paramétrés sont effacés au moment de l'exécution, l'objet de classe pour la classe sera le même que pour la classe & Lt; List & Lt; Integer & Gt; & Gt; et classe < Liste < Chaîne > >.

La raison pour laquelle vous ne pouvez pas les instancier avec la notation .class est qu’il s’agit d’une syntaxe spéciale utilisée pour les littéraux de classe. La spécification du langage Java l'interdit spécifiquement. syntaxe lorsque le type est paramétré, raison pour laquelle List < String > .class n'est pas autorisé.

Autres conseils

Les classes représentent les classes chargées par un chargeur de classes, qui sont des types bruts. Pour représenter un type paramétré, utilisez java.lang.reflect.ParameterizedType.

Je ne pense pas que vous puissiez faire ce que vous essayez. Tout d'abord, votre méthode instanciée ne sait pas qu'elle traite avec un type paramétré (vous pouvez tout aussi bien le transmettre à java.util.Date.class). Deuxièmement, en raison de l’effacement, il est difficile, voire impossible, de faire quelque chose de particulièrement spécifique avec les types paramétrés au moment de l’exécution.

Si vous deviez aborder le problème différemment, vous pouvez effectuer d'autres petites astuces, comme l'inférence de type:

public class GenTest
{
    private static <E> List<E> createList()
    {
        return new ArrayList<E>();
    }

    public static void main(String[] args)
    {
        List<String> list = createList();
        List<Integer> list2 = createList();
    }
}

La seule chose à faire est d'instancier List<String> directement et d'appeler son getClass():

.
instantiate(new List<String>() { ... }.getClass());

Pour les types avec plusieurs méthodes abstraites telles que List, cela est assez compliqué. Mais malheureusement, l'appel de constructeurs de sous-classes (comme new ArrayList<String>) ou de méthodes d'usine (Collections.<String>emptyList()) ne fonctionne pas.

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top