Java: Instance de et génériques

Avant de parcourir la structure de données générique d’un index de valeur, j’aimerais savoir si c’est même une instance du type this a été paramétrée.

Mais Eclipse se plaint quand je fais ceci:

 @Override public int indexOf(Object arg0) { if (!(arg0 instanceof E)) { return -1; } 

Ceci est le message d’erreur:

Impossible d’effectuer une vérification d’instance par rapport au paramètre de type E. Utilisez plutôt son object d’effacement car les informations de type générique seront effacées lors de l’exécution

Quelle est la meilleure façon de le faire?

    Le message d’erreur dit tout. Au moment de l’exécution, le type a disparu, il n’y a aucun moyen de le vérifier.

    Vous pouvez l’attraper en créant une fabrique pour votre object comme ceci:

      public static  MyObject createMyObject(Class type) { return new MyObject(type); } 

    Et puis, dans le constructeur de l’object, stockez ce type, si variable que votre méthode pourrait ressembler à ceci:

      if (arg0 != null && !(this.type.isAssignableFrom(arg0.getClass())) { return -1; } 

    Deux options pour la vérification de type à l’exécution avec des génériques:

    Option 1 – corrompre votre constructeur

    Supposons que vous écrasiez indexOf (…) et que vous souhaitiez vérifier le type uniquement pour les performances, pour vous épargner l’itération de la collection entière.

    Faites un constructeur sale comme ceci:

     public MyCollection(Class t) { this.t = t; } 

    Ensuite, vous pouvez utiliser isAssignableFrom pour vérifier le type.

     public int indexOf(Object o) { if ( o != null && !t.isAssignableFrom(o.getClass()) ) return -1; //... 

    Chaque fois que vous instanciez votre object, vous devrez vous répéter:

     new MyCollection(Apples.class); 

    Vous pourriez décider que cela ne vaut pas la peine. Dans l’implémentation de ArrayList.indexOf (…) , ils ne vérifient pas que le type correspond.

    Option 2 – Laisse tomber

    Si vous avez besoin d’utiliser une méthode abstraite qui nécessite votre type inconnu, tout ce que vous voulez, c’est que le compilateur cesse de pleurer sur instanceof . Si vous avez une méthode comme celle-ci:

     protected abstract void abstractMethod(T element); 

    Vous pouvez l’utiliser comme ceci:

     public int indexOf(Object o) { try { abstractMethod((T) o); } catch (ClassCastException e) { //... 

    Vous lancez l’object dans T (votre type générique), juste pour tromper le compilateur. Votre dissortingbution ne fait rien à l’exécution , mais vous obtiendrez toujours une exception ClassCastException lorsque vous essayez de passer le type d’object incorrect dans votre méthode abstraite.

    REMARQUE 1: Si vous effectuez des lancements non vérifiés supplémentaires dans votre méthode abstraite, vos ClassCastExceptions seront interceptées ici. Cela peut être bon ou mauvais, alors réfléchissez bien.

    REMARQUE 2: Vous obtenez une vérification NULL gratuite lorsque vous utilisez instanceof . Comme vous ne pouvez pas l’utiliser, vous devrez peut-être vérifier nullement avec vos propres mains.

    Si votre classe étend une classe avec un paramètre générique, vous pouvez également l’obtenir lors de l’exécution via la reflection, puis l’utiliser pour la comparaison, c’est-à-dire

     class YourClass extends SomeOtherClass { private Class clazz; public Class getParameterizedClass() { if(clazz == null) { ParameterizedType pt = (ParameterizedType)this.getClass().getGenericSuperclass(); clazz = (Class)pt.getActualTypeArguments()[0]; } return clazz; } } 

    Dans le cas ci-dessus, lors de l’exécution, vous obtiendrez Ssortingng.class à partir de getParameterizedClass (), et il met en cache afin que vous n’obteniez aucune surcharge de reflection lors de plusieurs vérifications. Notez que vous pouvez obtenir les autres types paramétrés par index à partir de la méthode ParameterizedType.getActualTypeArguments ().

    Ancien message, mais un moyen simple de faire une vérification générique des instances.

     public static  boolean isInstanceOf(Class clazz, Class targetClass) { return clazz.isInstance(targetClass); } 

    J’ai eu le même problème et voici ma solution (très humble, @george: cette fois en compilant ET en travaillant …).

    Mon probem était dans une classe abstraite qui implémente Observer. La méthode Observable déclenche la mise à jour (…) avec la classe Object qui peut être n’importe quel type d’object.

    Je veux seulement manipuler des objects de type T

    La solution consiste à transmettre la classe au constructeur afin de pouvoir comparer les types à l’exécution.

     public abstract class AbstractOne implements Observer { private Class tClass; public AbstractOne(Class clazz) { tClass = clazz; } @Override public void update(Observable o, Object arg) { if (tClass.isInstance(arg)) { // Here I am, arg has the type T foo((T) arg); } } public abstract foo(T t); } 

    Pour l’implémentation, il suffit de passer la classe au constructeur

     public class OneImpl extends AbstractOne { public OneImpl() { super(Rule.class); } @Override public void foo(Rule t){ } } 

    Ou vous pourriez attraper une tentative ratée de lancer dans E par exemple.

     public int indexOf(Object arg0){ try{ E test=(E)arg0; return doStuff(test); }catch(ClassCastException e){ return -1; } } 

    Techniquement, vous ne devriez pas avoir à le faire, c’est le but des génériques, vous pouvez donc faire une vérification de type compilation:

     public int indexOf(E arg0) { ... } 

    mais alors le @Override peut être un problème si vous avez une hiérarchie de classes. Sinon, voir la réponse de Yishai.

    Le type d’exécution de l’object est une condition relativement arbitraire à filtrer. Je suggère de garder une telle apparence loin de votre collection. Cela se fait simplement en déléguant votre collection à un filtre transmis dans une construction.

     public interface FilterObject { boolean isAllowed(Object obj); } public class FilterOptimizedList implements List { private final FilterObject filter; ... public FilterOptimizedList(FilterObject filter) { if (filter == null) { throw NullPointerException(); } this.filter = filter; } ... public int indexOf(Object obj) { if (!filter.isAllows(obj)) { return -1; } ... } ... } final List longStrs = new FilterOptimizedList( new FilterObject() { public boolean isAllowed(Object obj) { if (obj == null) { return true; } else if (obj instanceof Ssortingng) { Ssortingng str = (Ssortingng)str; return str.length() > = 4; } else { return false; } }} );