Pourquoi ne puis-je pas transmettre explicitement l'argument de type à une méthode Java générique ?

StackOverflow https://stackoverflow.com/questions/24991

  •  09-06-2019
  •  | 
  •  

Question

J'ai défini une fonction Java :

static <T> List<T> createEmptyList() {
    return new ArrayList<T>();
}

Une façon de l'appeler est la suivante :

List<Integer> myList = createEmptyList(); // Compiles

Pourquoi ne puis-je pas l'appeler en passant explicitement l'argument de type générique ?:

Object myObject = createEmtpyList<Integer>(); // Doesn't compile. Why?

j'obtiens l'erreur Illegal start of expression du compilateur.

Était-ce utile?

La solution

Lorsque le compilateur Java ne peut pas déduire lui-même le type de paramètre pour une méthode statique, vous pouvez toujours le transmettre en utilisant le nom complet de la méthode :Classe .<Type> méthode();

Object list = Collections.<String> emptyList();

Autres conseils

Vous pouvez, si vous transmettez le type en tant que paramètre de méthode.

static <T> List<T> createEmptyList( Class<T> type ) {
  return new ArrayList<T>();
}

@Test
public void createStringList() {
  List<String> stringList = createEmptyList( String.class );
}

Les méthodes ne peuvent pas être génériques de la même manière qu'un type, donc la seule option pour une méthode avec un type de retour générique typé dynamiquement - ouf c'est une bouchée :-) - est de transmettre le type comme argument.

Pour une FAQ vraiment excellente sur les génériques Java, voir la FAQ sur les génériques d'Angelika Langer.

.
.

Suivi:

Cela n'aurait aucun sens dans ce contexte d'utiliser l'argument tableau comme dans Collection.toArray( T[] ).La seule raison pour laquelle un tableau est utilisé est que le même tableau (pré-alloué) est utilisé pour contenir les résultats (si le tableau est suffisamment grand pour les contenir tous).Cela évite d'allouer à tout moment un nouveau tableau au moment de l'exécution.

Cependant, à des fins pédagogiques, si vous souhaitez utiliser le typage tableau, la syntaxe est très similaire :

static <T> List<T> createEmptyList( T[] array ) {
  return new ArrayList<T>();
}

@Test
public void testThing() {
  List<Integer> integerList = createEmptyList( new Integer[ 1 ] );
}

Cela faisait un certain temps que je n'avais pas exploré ces parties de Java, mais...

La raison pour laquelle vous ne pouvez pas le faire était probablement un choix de conception des développeurs du langage.Pourtant, en raison du tapez l'effacement utilisé par Java, les informations génériques sont de toute façon supprimées au moment de la compilation, donc dans votre exemple, cela créerait exactement le même code d'octet, que vous ayez ou non le paramètre de type.

@pauldoo Oui, vous avez tout à fait raison.C’est l’une des faiblesses des génériques Java à mon humble avis.

En réponse à Cheekysoft, j'aimerais proposer de regarder également comment cela est fait par les utilisateurs Java eux-mêmes, comme T[] Collection abstraite#toArray(T[] une).Je pense que la version de Cheekysofts est supérieure, mais celle de Java a l'avantage d'être familière.

Modifier:Lien ajouté.Rééditer :J'ai trouvé un bug sur SO :)


Suivi sur Cheekysoft :Eh bien, comme il s'agit d'une liste d'un certain type qui doit être renvoyée, l'exemple correspondant devrait ressembler à ceci :

static <T> List<T> createEmptyList( List<T> a ) {
  return new ArrayList<T>();
}

Mais oui, passer l'objet de classe est clairement le meilleur.Mon seul argument est celui de la familiarité, et dans ce cas précis, cela ne vaut pas grand-chose (en fait, c'est mauvais).

Licencié sous: CC-BY-SA avec attribution
Non affilié à StackOverflow
scroll top