J'ai;
List stringList = new ArrayList();
List integerList = new ArrayList();
Existe-t-il un moyen (facile) de récupérer le type générique de la liste ?
J'ai;
List stringList = new ArrayList();
List integerList = new ArrayList();
Existe-t-il un moyen (facile) de récupérer le type générique de la liste ?
Si ce sont effectivement des champs d'une certaine classe, vous pouvez les obtenir avec un peu d'aide de la réflexion:
package com.stackoverflow.q1942644;
import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.util.ArrayList;
import java.util.List;
public class Test {
List stringList = new ArrayList<>();
List integerList = new ArrayList<>();
public static void main(String... args) throws Exception {
Class testClass = Test.class;
Field stringListField = testClass.getDeclaredField("stringList");
ParameterizedType stringListType = (ParameterizedType) stringListField.getGenericType();
Class stringListClass = (Class) stringListType.getActualTypeArguments()[0];
System.out.println(stringListClass); // class java.lang.String
Field integerListField = testClass.getDeclaredField("integerList");
ParameterizedType integerListType = (ParameterizedType) integerListField.getGenericType();
Class integerListClass = (Class) integerListType.getActualTypeArguments()[0];
System.out.println(integerListClass); // class java.lang.Integer
}
}
Vous pouvez également le faire pour les types de paramètres et le type de retour des méthodes.
Mais s'ils se trouvent dans le même contexte de la classe/méthode où vous en avez besoin, alors il n'y a pas d'intérêt à les connaître, car vous les avez déjà déclarés vous-même.
While this is definitely an interesting exercise in generics, if you now what field you want, you usually know what type it is.. :) Determining the type of a parameter would've been a lot more useful I suppose. Good when making injection frameworks or similar though. +1
Il y a certainement des situations où cela est plus que utile. Par exemple, dans les frameworks ORM sans configuration.
..qui peut utiliser Class#getDeclaredFields() pour obtenir tous les champs sans avoir besoin de connaître le nom du champ.
Vous pouvez faire de même pour les paramètres de méthode également :
Method method = someClass.getDeclaredMethod("someMethod");
Type[] types = method.getGenericParameterTypes();
//Maintenant, en supposant que le premier paramètre de la méthode est de type List
ParameterizedType pType = (ParameterizedType) types[0];
Class clazz = (Class) pType.getActualTypeArguments()[0];
System.out.println(clazz); //affiche java.lang.Integer
Réponse courte : non.
C'est probablement un doublon, je ne trouve pas le bon en ce moment.
Java utilise quelque chose appelé effacement de type, ce qui signifie qu'à l'exécution, les deux objets sont équivalents. Le compilateur sait que les listes contiennent des entiers ou des chaînes de caractères, et peut donc maintenir un environnement sûr en termes de type. Cette information est perdue (au niveau de l'instance de l'objet) à l'exécution, et la liste ne contient que des 'Objets'.
Vous POUVEZ découvrir un peu sur la classe, quels types elle pourrait être paramétrée par, mais normalement il s'agit juste de tout ce qui étend "Object", c'est-à-dire n'importe quoi. Si vous définissez un type comme
class AClass {....}
AClass.class contiendra seulement le fait que le paramètre A est borné par MyClass, mais au-delà de ça, il n'y a aucun moyen de le savoir.
Si vous avez besoin d'obtenir le type générique d'un type retourné, j'ai utilisé cette approche lorsque j'avais besoin de trouver des méthodes dans une classe qui retournait une Collection
et d'accéder ensuite à leurs types génériques :
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Collection;
import java.util.List;
public class Test {
public List test() {
return null;
}
public static void main(String[] args) throws Exception {
for (Method method : Test.class.getMethods()) {
Class returnClass = method.getReturnType();
if (Collection.class.isAssignableFrom(returnClass)) {
Type returnType = method.getGenericReturnType();
if (returnType instanceof ParameterizedType) {
ParameterizedType paramType = (ParameterizedType) returnType;
Type[] argTypes = paramType.getActualTypeArguments();
if (argTypes.length > 0) {
System.out.println("Generic type is " + argTypes[0]);
}
}
}
}
}
}
Cela génère :
Type générique est class java.lang.String
À l'exécution, non, vous ne pouvez pas.
Cependant, via la réflexion, les paramètres de type sont accessibles. Essayez
for(Field field : this.getDeclaredFields()) {
System.out.println(field.getGenericType())
}
La méthode getGenericType()
retourne un objet Type. Dans ce cas, ce sera une instance de ParametrizedType
, qui a à son tour des méthodes getRawType()
(qui contiendra List.class
, dans ce cas) et getActualTypeArguments()
, qui renverra un tableau (dans ce cas, de longueur un, contenant soit String.class
soit Integer.class
).
Et cela fonctionne-t-il pour les paramètres reçus par une méthode au lieu des champs d'une classe ???
@opensas Vous pouvez utiliser method.getGenericParameterTypes()
pour obtenir les types déclarés des paramètres d'une méthode.
Cela fonctionne parfaitement jusqu'à ce que vous ayez, disons, class Foo { public T bar; } Foo fooField;
- dans ce cas, ce qui est renvoyé pour le membre 'bar' de fooField sera un TypeVariable au lieu d'une Classe. Même si vous et moi pouvons clairement voir que T sera Integer, pour une raison quelconque, nous ne pouvons récupérer cette information que de manière réflexive à partir d'une sous-classe de Foo en utilisant la méthode getGenericSuperclass de la sous-classe (qui renverra ensuite un ParametrizedType comme dans l'exemple ci-dessus).
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.
0 votes
Pour pouvoir inspecter de manière programmatique un objet de type List et voir son type générique. Une méthode peut vouloir insérer des objets en fonction du type générique de la collection. Cela est possible dans les langages qui implémentent des génériques au moment de l'exécution plutôt qu'au moment de la compilation.
4 votes
Correct -- à peu près la seule façon de permettre la détection en temps d'exécution est par sous-classement : vous POUVEZ réellement étendre le type générique puis, à l'aide de la réflexion, trouver la déclaration de type que la sous-type a utilisée. Cela demande beaucoup de réflexion, mais c'est possible. Malheureusement, il n'y a pas de moyen facile d'imposer l'utilisation d'une sous-classe générique.
1 votes
Surely stringList contains strings and integerList integers? Why make it more complicated?