49 votes

Classe générique Java - Déterminer le type

Si je crée une classe java pour être générique, tels que:

public class Foo<T>

Comment peut-on déterminer de manière interne à la classe, ce qui T " a fini par être?

public ???? Bar()
{
    //if its type 1
    //    do this
    //if its type 2
    //    do this
    //if its type 3
    //    do this
    //if its type 4
    //    do this
}

J'ai tourné autour de l'API Java et joue avec le Reflet des choses, instanceof, getClass, .de classe, etc, mais je n'arrive pas à faire des têtes ou queues d'entre eux. Je sens que je suis proche et juste besoin de combiner un certain nombre d'appels, mais garder à venir court.

Pour être plus précis, je cherche à déterminer si la classe est instanciée avec l'un des 3 types possibles.

58voto

jnt30 Points 878

J'ai utilisé une solution similaire à celle qu'il explique ici pour quelques projets et je l'ai trouvée très utile.

http://blog.xebia.com/2009/02/07/acessing-generic-types-at-runtime-in-java/

Le jist utilise les éléments suivants:

  public Class returnedClass() {
     ParameterizedType parameterizedType = (ParameterizedType)getClass()
                                                 .getGenericSuperclass();
     return (Class) parameterizedType.getActualTypeArguments()[0];
}
 

44voto

Daniel Schneller Points 6417

En contraste .NET, Java génériques sont mis en œuvre par une technique dite de type "effacement".

Ce que cela signifie, c'est que le compilateur utilisera le type d'informations lors de la génération des fichiers de classe, mais pas le transfert de cette information pour le byte code. Si vous regardez les classes compilées avec javap ou d'autres outils similaires, vous trouverez que List<String> est un simple List (de Object) dans le fichier de classe, comme il était en pré-Java-5 du code.

Code d'accès à la Liste générique sera "réécrit" par le compilateur d'inclure la jette, vous devez écrire vous-même dans les versions antérieures. En effet, la suite de deux fragments de code sont identiques d'un octet de code perspective, une fois que le compilateur est fait avec eux:

Java 5:

List<String> stringList = new ArrayList<String>();
stringList.add("Hello World");
String hw = stringList.get(0);

Java 1.4 et avant:

List stringList = new ArrayList();
stringList.add("Hello World");
String hw = (String)stringList.get(0);

Lors de la lecture des valeurs à partir d'une classe générique en Java 5 le nécessaire de lancer pour le type déclaré paramètre est automatiquement inséré. Lors de l'insertion, le compilateur vérifiera la valeur que vous essayez de les mettre dans l'abandon et avec une erreur si elle n'est pas une Chaîne.

Le tout a été fait pour garder les anciens des bibliothèques et de la nouvelle generified code interopérables, sans avoir à recompiler l'existant libs. C'est un avantage majeur sur le .NET moyen, où les classes génériques et non génériques vivre côte-à-côte, mais ne peuvent pas être échangées librement.

Les deux approches ont leurs avantages et leurs inconvénients, mais c'est la façon dont il est en Java.

Pour en revenir à votre question initiale: Vous ne serez pas en mesure d'obtenir les informations de type à l'exécution, parce que simplement, il n'est plus là, une fois que le compilateur a fait son travail. C'est sûrement la limitation à certains égards, et il y a quelques grincheux des moyens autour d'elle qui sont généralement basés sur le stockage de classe-instance quelque part, mais ce n'est pas une fonction standard.

12voto

Michael Myers Points 82361

En raison du type d'effacement, il n'y a aucun moyen de le faire directement. Ce que vous pouvez faire, cependant, est de passer un Class<T> dans le constructeur et le retenir à l'intérieur de votre classe. Ensuite, vous pouvez vérifier contre l'un des trois Class types qui vous permettent.

Cependant, s'il y a seulement trois types possibles, vous pourriez envisager de refactoring dans un enum à la place.

3voto

Janusz Points 52607

Le problème est que la plupart des éléments génériques disparaissent pendant la compilation.

Une solution courante consiste à enregistrer le type lors de la création de l'objet.

Pour une brève introduction au comportement des types java de java, lisez cette page.

1voto

Ryan Shillington Points 558

Si vous connaissez quelques types spécifiques significatifs, vous devez créer des sous-classes de votre type générique avec l'implémentation.

Alors

 public class Foo<T>

public ???? Bar()
{
    //else condition goes here
}
 

Et alors

 public class DateFoo extends Foo<Date>

public ???? Bar()
{
    //Whatever you would have put in if(T == Date) would go here.
}
 

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