2 votes

Créer une classe générique par simple argument de type ?

Comment puis-je créer une classe générique qui prend le type de classe de l'argument de type générique qui est placé lors de la création/injection de cette classe générique ? Mon but est de spécifier eg MyGeneric<User> et la classe générique devrait alors être capable d'utiliser la fonction User dans tous les appels de méthode. Sans avoir à fournir explicitement des User.class dans le constructeur du générique additionnel.

Quelque chose comme :

class MyGeneric<T> {
    public MyGeneric() {
        someService.create(Class<T>, someString);
    }
}

class Usage {
    @Inject
    MyGeneric<User> myuser;
}

Comment procéder correctement ?

2voto

Bohemian Points 134107

Il n'y a aucun moyen de le faire, en raison de la durée d'exécution. type d'effacement .

La méthode habituelle consiste (comme vous y avez fait allusion) à passer une instance de Class<T> - appelé type de jeton - au constructeur. Compte tenu de votre modèle de code, vous êtes coincé avec cette approche.

0voto

openCage Points 1011

C'est un peu délicat mais avec par exemple TypeLiteral de Guice vous pouvez faire des choses comme :

public class ReiHashMap<K,V> extends HashMap<K,V> {

   private final TypeLiteral<K> keyTL;

   public ReiHashMap(TypeLit<K> keyTL ) {
       this.keyTL = keyTL;
   }

   @Override
   public V get(Object o) {
       if ( !keyTL.getRawType().isAssignableFrom( o.getClass() )) {
           throw new IllegalArgumentException( "object " + o + " (class "+ o.getClass() +")ist not of type " + keyTL);
       }
       return super.get(o);
   }
   ...

Il s'agit d'une extension de HashMaps qui permet de vérifier le type de l'argument de get au moment de l'exécution.

0voto

Costi Ciudatu Points 13020

Ce que vous pouvez faire, c'est écrire le code d'instanciation dans une superclasse, puis l'étendre pour chaque type générique particulier (peu ou pas de code est nécessaire dans les sous-classes, mais les sous-classes sont obligatoires car elles sont le seul moyen d'éviter l'effacement des types) :

abstract class MyGeneric<T> {

    private T instance;

    public MyGeneric(String str) {
        // grab the actual class represented by 'T'
        // this only works for subclasses of MyGeneric<T>, not for MyGeneric itself !
        Class<T> genericType = (Class<T>) ((ParameterizedType)getClass().getGenericSuperclass())
                .getActualTypeArguments()[0];
        try {
            // instantiate that class with the provided parameter
            instance = genericType.getConstructor(String.class).newInstance(str);
        } catch (Exception e) {
            throw new IllegalArgumentException(e);
        }
    }
}

class MyUser extends MyGeneric<User> {
    public MyUser() {
        // provide the string to use for instantiating users...
        super("userStr");
    }
}

class User { /*...*/ }

Edit : création de la classe générique abstract pour imposer l'utilisation de sous-classes.

Il peut également être utilisé avec des classes anonymes comme :

new MyGeneric<User>("..string...") {}

Je pense que c'est ce qui se rapproche le plus de votre objectif initial...

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X