Comment créer un littéral de classe d'un type connu: Class>


Prenez ce qui suit:

public Class<List<String>> getObjectType() {
    // what can I return here?
}

Quelle expression littérale de classe puis-je retourner de cette méthode qui satisfera les génériques et compilera? List.class ne compilera pas, et List.<String>class non plus.

Si vous vous demandez "pourquoi", j'écris une implémentation de Spring's FactoryBean<List<String>>, qui m'oblige à implémenter Class<List<String>> getObjectType(). Cependant, ceci est pas une question de printemps.

Edit: Mes cris plaintifs ont été entendus par les puissances qui sont à SpringSource, et donc Spring 3.0.1 aura le type de retour de getObjectType() changé en Class<?>, ce qui évite soigneusement le problème.

Author: axiopisty, 2010-01-06

10 answers

Vous pouvez toujours lancer ce dont vous avez besoin, comme ceci

return (Class<List<String>>) new ArrayList<String>().getClass();

Ou

return (Class<List<String>>) Collections.<String>emptyList().getClass();

Mais je suppose que ce n'est pas ce que vous recherchez. Eh bien, cela fonctionne, avec un avertissement, mais ce n'est pas exactement "beau".

Je viens de trouver ce

Pourquoi n'y a-t-il pas de littéral de classe pour les types paramétrés génériques?

Car un type paramétré générique n'a pas de représentation exacte du type d'exécution.

Donc le casting pourrait être la seule façon d'aller.

 38
Author: Bozho, 2015-10-17 10:58:59

, Vous ne devez jamais utiliser la construction Class<List<String>>. C'est absurde et devrait produire un avertissement en Java (mais pas). Les instances de classe représentent toujours des types bruts, vous pouvez donc avoir Class<List>; c'est tout. Si vous voulez que quelque chose représente un type générique réifié comme List<String> , vous avez besoin d'un "jeton super type" comme Guice utilise:

Http://google-guice.googlecode.com/git/javadoc/com/google/inject/TypeLiteral.html

 15
Author: Kevin Bourrillion, 2013-03-11 09:48:25

L'existence d'un Class<List<String>> est intrinsèquement dangereux. voici pourquoi:

// This statement generates a warning - for a reason...
Class<List<String>> unsafeListClass = (Class<List<String>>) (Class<?>) List.class;

List<Integer> integerList = new ArrayList<Integer>(); // Ok
integerList.add(42); // Ok

System.out.println(unsafeListClass.isInstance(integerList)); // Prints "true".
List<String> stringList =
   unsafeListClass.cast(integerList); // Succeeds, with no warning!
stringList.add("Hello, World!"); // Also succeeds with no warning

for (int x: integerList) {
    // Compiles without warning, but throws ClassCastException at runtime
    System.out.println(100-x);
}
 7
Author: finnw, 2010-02-12 00:12:25

A ce lien sur springframework.org ce qui donne un aperçu.

Par exemple

List<String> myList = new ArrayList<String>();
return (Class<List<String>>)myList.getClass();
 6
Author: JRL, 2010-01-06 11:17:32

Vous pouvez implémenter cette méthode comme ceci:

public Class<List<String>> getObjectType() {
    return (Class<List<String>>) ((Class)List.class);
}
 4
Author: Saeed Zarinfam, 2014-04-13 16:15:40

Découvrez cette discussion sur les forums SUN:

Http://forums.sun.com/thread.jspa?threadID=5253007

Et l'article de blog référencé qui décrit une solution de contournement en utilisant des "jetons de type super":

Http://gafter.blogspot.com/2006/12/super-type-tokens.html

 2
Author: Mike Tunnicliffe, 2010-01-06 11:21:55

Je ne sais pas si cela est possible du tout, car tout littéral de classe sera compilé en Class.forName(...) et puisque cela se produit lors de l'exécution, il ne reste aucune information générique.

 1
Author: perdian, 2010-01-06 11:08:36

Je ne suis pas sûr mais la question suivante que j'ai posée pourrait être pertinente pour vous...

Java generics type paramètres et opérations sur ces types

 0
Author: Yaneeve, 2017-05-23 12:02:13

Qu'en est-il de ceci:

public class TestMain {
    public static void main(String[] args) throws Exception {
        Type type = TestMain.class.getMethod("dummy").getGenericReturnType();
        System.out.println("type = " + type);
    }

    public List<Integer> dummy() {return null;}
}

Ceci imprime:

type = java.util.List<java.lang.Integer>
 0
Author: mazi, 2013-05-09 09:11:52

L'approche suivante est problématique:

> public Class<List<String>> getModelType() {
>   return (Class<List<String>>) new ArrayList<String>().getClass();
> }

Par exemple si vous voulez tester si un objet dit de type

org.eclipse.emf.common.util.BasicEList<String> 

Est de type

List<String> 

Basé sur le résultat de l'approche getModelType() susmentionnée, par exemple:

BasicEList<String> fromObject = ...;
if (getModelType().isAssignableFrom(fromObject.getClass())) {
    transferFromModelToUi(getModelType().cast(fromObject));
}

Cela entraînera false alors qu'il devrait être true car les deux objets implémentent la liste d'interface (puisque getModelType() renvoie un objet de classe de type List et non ArrayList).

Voici une approche qui a fonctionné pour moi (a bit lourd mais conduit à des résultats corrects dans l'exemple ci-dessus, pourrait être déplacé vers un initialiseur statique):

public Class<List<String>> getModelType() {
    Class<?> arrayListClass = new ArrayList<String>().getClass();
    Class<?>[] interfaces = arrayListClass.getInterfaces();
    int index = 0;
    for (int i = 0; i < interfaces.length; i++) {
        if (interfaces[i].equals(List.class)) {
            index = i;
            break;
        }
    }
    return (Class<List<String>>) interfaces[index];
}
 0
Author: Lukas Z., 2014-03-28 08:49:39