Bizarre génériques comportement de la Liste.toArray(T[])
Je suis tombé sur quelque chose de très basique, mais très déconcertant aujourd'hui. J'avais besoin de convertir une liste à un tableau. La liste contenue String
instances. Parfait exemple de l'utilisation de List.toArray(T[])
, car je voulais un String[]
instance. Cela ne fonctionnerait pas, cependant, sans explicitement le casting du résultat de String[]
.
Comme un scénario de test, j'ai utilisé le code suivant:
import java.util.Arrays;
import java.util.List;
public class MainClass {
public static void main(String args[]) {
List l = Arrays.asList("a", "b", "c");
String stuff[] = l.toArray(new String[0]);
System.err.println(Arrays.asList(stuff));
}
}
qui ne compile pas. C'est presque une copie exacte de l'exemple de la javadoc, mais le compilateur dit ce qui suit:
MainClass.java:7: incompatible types
found : java.lang.Object[]
required: java.lang.String[]
String stuff[] = l.toArray(new String[0]);
^
Si j'ajoute un casting pour String[]
de compiler ET de l'exécuter parfaitement. Mais ce n'est pas ce que j'attends, quand j'ai vu la signature de la méthode toArray:
<T> T[] toArray(T[] a)
Cela me dit que je ne devrais pas avoir à jeter. Ce qui se passe?
Edit:
Curieusement, si je change la déclaration de la liste à:
List<?> l = Arrays.asList("a", "b", "c");
il fonctionne également. Ou List<Object>
. Donc il n'a pas à être un List<String>
comme l'avait suggéré. Je commence à penser que l'utilisation du raw List
type modifie la perception de méthodes génériques à l'intérieur que le travail en classe.
Deuxième edit:
Je pense que je l'obtenir maintenant. Ce que Tom Hawtin a écrit dans un commentaire ci-dessous semble être la meilleure explication. Si vous utilisez un type générique dans le raw façon, tous les génériques de l'information à partir de cette instance seront effacées par le compilateur.
Vous devez vous connecter pour publier un commentaire.
vous avez oublié de spécifier le paramètre de type de votre Liste:
dans ce cas, vous pouvez écrire la sécurité:
sans n'importe quelle distribution.
l
. Donc T est comme Objet (l'implicite lié).l.toArray(new String[l.size()]);
, pour éviter de redundant array redimensionnement à l'aide de la réflexion.ou ne
toujours étrange
cela permettra de compiler, vous êtes à l'aide de médicaments génériques à dire "ceci est une liste de Chaînes" de sorte que la méthode toArray sait de quel type de tableau à retourner.
C'est parce que votre liste contient des objets, pas des chaînes de caractères. Aviez-vous déclaré votre liste
List<String>
, le compilateur serait heureux.List
sans un type déclaré par défaut "Liste d'Objets", tandis queList<?>
signifie "Liste de l'inconnu". Dans le monde de types génériques, il est un fait que la "Liste d'Objets" est différent de "Liste de Chaîne", mais le compilateur ne peut pas dire la même chose pour la Liste des "inconnus". Si vous avez déclaré que l'inconnu puis, aussi loin que le compilateur ne peut pas savoir, c'est OK.Le point principal est que déclarer que quelque chose comme le générique ? est différente de la déclarer comme Objet. Lire plus sur les caractères génériques ici