2017-10-19 6 views
8

J'ai la classe suivante:Java - Utiliser le paramètre de classe dans le paramètre de la méthode

public class Publisher<T> { 

    private static final Class[] SUPPORTED_CLASSES = new Class[]{T1.class, T2.class}; 

    public Publisher() { 
     if(Arrays.asList(SUPPORTED_CLASSES).contains(T)) { // error: expression expected! 
      System.out.println("Class not supported!"); 
     } 
    } 
} 

Comment puis-je vérifier si le paramètre de classe est conforme à la mise en œuvre?
Dans l'exemple ci-dessus, je ne peux pas utiliser le paramètre de classe T en tant que paramètre.

+0

Vérifiez ce fil https://stackoverflow.com/questions/3403909/get-generic-type-of-class-at-runtime –

+3

Pourquoi voulez-vous cela, si je peux demander? –

+0

@MCEmperor Je voulais vérifier si la classe est prise en charge et enregistrer un message d'avertissement si nécessaire – FazoM

Répondre

13

Pourquoi cela ne fonctionne pas

Vous essayez d'accéder à un type générique lors de l'exécution, ce qui ne fonctionne pas dans ce cas, à cause de type erasure.

Comment fixer

La façon la plus simple de résoudre ce problème est de prendre un Class<T> dans le constructeur, qui vous donnera le type au moment de l'exécution, vous pouvez alors vérifier si la liste contient la valeur que vous avez donné .

code Exemple

public Publisher(Class<T> clazz) { 
    if(!SUPPORTED_CLASSES.contains(clazz)) { 
     System.out.println("Class not supported!"); 
    } 
} 

Problèmes possibles

Votre code ne supporte pas les sous-types, ce qui peut causer des problèmes, à moins que vous êtes ok avec ce (vous pouvez travailler sur les listes, mais pas nécessairement ArrayLists) , ceci fait le LSP cependant.

+0

Je dirais qu'une raison encore plus fondamentale pourquoi le code de l'OP ne fonctionne pas est que les arguments de type tels que' T' désignent * types * , pas d'objets.En particulier, ils ne sont pas identiques et ne représentent pas les objets de type 'java.lang.Class', tels que ceux du tableau OP. Les types ne sont pas des arguments ordinaires valides. –

+0

LSP est seulement un problème si la classe de OP est supposée être covariante dans T. Si elle est contra- ou invariante, c'est une façon de faire totalement légale (si bizarre et non-OOP). – Kevin

4

Vous aurez besoin de passer la classe dans le constructeur:

public Publisher(Class<T> clazz) { 
    if(!SUPPORTED_CLASSES.contains(clazz)) { 
     System.out.println("Class not supported!"); 
    } 
} 

parce T n'est pas disponible lors de l'exécution: exactement le même code sera exécuté pour new Publisher<T1>() et new Publisher<T3>().

6

Bien que d'autres réponses sont assez bien, je voudrais proposer une autre solution de contournement:

Vous pouvez créer une interface vide MyInterface, et ont toutes les classes dans votre liste implémenter cette interface. Ensuite, vous pouvez modifier votre déclaration de classe à:

qui atteindra votre objectif.

+1

Ceci est une meilleure solution si vous avez le contrôle de toutes les classes que vous devez prendre en charge, mais si vous avez besoin de prendre en charge des classes que vous n'avez pas écrites, vous devrez peut-être le faire différemment. – jrtapsell

+1

@jrtapsell dans le pire des cas, si vous n'avez pas à supporter trop de classe, en utilisant un pont pour chaque classe dont vous avez besoin (un simple wrapper en fait) implémentant l'interface – AxelH

+0

Lorsque votre solution ne fonctionne qu'avec des classes implémentant un interface, vous n'avez plus besoin de cette liste de classes compatibles et pouvez simplement déclarer la classe comme public class Publisher ' – Philipp