J'ai fait une critique de code pour mon collègue il y a deux jours. Je sentais que je n'avais pas une bonne compréhension des génériques Java, alors j'ai sorti le livre "Effective Java" 1, puis j'ai regardé les chapitres concernés. Dans le point 24: Éliminez la section des avertissements non contrôlés, l'auteur utilise la méthode publique <t> t [] toarray (t [] a) dans la classe ArrayList comme exemple pour illustrer comment utiliser @SuppressWarnings Annotation pour les variables.
ArrayList est une classe générique, qui est déclarée comme ceci:
Javapublic Class ArrayList <E> étend AbstractList <e> implémente List <e>, RandomAccess, Clonable, Java.io.Serializable
La méthode ToArray (t [] a) de cette classe est une méthode générique, qui est déclarée et implémentée comme ceci:
@SuppressWarnings ("non coché") public <T> t [] toArray (t [] a) {if (a.length <size) // faire un nouveau tableau de type d'exécution de A, mais mon contenu: return (t []) arrays.copyof (elementData, size, a.getClass (); taille) a [size] = null; retour a;} Cette méthode est en fait déclarée dans l'interface de collecte. Parce que nous l'utilisons souvent via ArrayList, nous utiliserons ArrayList comme exemple ici.
1 Pourquoi est-il déclaré comme un type différent?
Ma question est: pourquoi cette méthode utilise-t-elle le type T au lieu du type E de ArrayList? Autrement dit, pourquoi cette méthode n'est-elle pas déclarée comme ceci:
Javapublic e [] toarray (e [] a);
Si les types sont les mêmes, l'erreur de type de paramètre peut être trouvée pendant la compilation. Si les types sont différents, il est facile de générer des erreurs d'exécution. Par exemple, le code suivant:
// Créer un arrayListlist <string> strlist = new ArrayList <string> (); strlist.add ("ABC"); strlist.add ("xyz"); // convertir le STRList actuel en un tableau numérique. Notez qu'il n'y a pas d'erreurs de compilation dans l'instruction suivante. Numéro [] numArray = strList.toArray (nouveau numéro [0]); Exécutez le code ci-dessus et la ligne 6 lancera une exception java.lang.arraystoreException.
Si la méthode TOARRAY utilise le type E, l'instruction 2 générera une erreur de compilation. Les erreurs de compilation sont plus conviviales que les erreurs d'exécution. De plus, l'objectif principal des génériques est d'éliminer les erreurs de conversion de type (classcastException) pendant la compilation. Cette méthode est le contraire. Est-ce un gros bug? J'ai rencontré un bug de Java, mais je ne peux toujours pas le croire.
Après avoir vérifié Internet, ce problème a été discuté à plusieurs reprises 2, 3, 4.
2 peut améliorer la flexibilité
Cette déclaration est plus flexible et peut convertir des éléments dans la liste actuelle en un tableau de types plus généraux. Par exemple, le type de liste actuel est entier, et nous pouvons convertir ses éléments en un tableau numérique.
List <Integer> intList = new ArrayList <Integer> (); intList.add (1); intList.add (2); nombre [] numArray = intList.toArray (nouveau numéro [0]);
Si cette méthode est déclarée type E, le code ci-dessus aura une erreur de compilation. Il semble qu'il serait plus approprié de déclarer la méthode comme suit:
Javapublic <t super e> t [] toarray (t [] a);
Cependant, la syntaxe comme <t Super E> n'existe pas en Java. Et même s'il existe, cela ne fonctionne pas pour les tableaux. C'est également pour cette raison que lors de l'utilisation de cette méthode, même si t est la classe parent de E, ou T est la même que E, java.lang.arraystoreException 5, 6, 7 ne peut pas être complètement évitée. Veuillez consulter les deux codes suivants. Dans le premier code, T est la classe parent de E, et dans le deuxième code, t est le même que E. Les deux éléments de code lancent des exceptions.
Code 1:
List <Integer> intList = new ArrayList <Integer> (); intList.add (1); intList.add (2); Float [] floatArray = new float [2]; // float est une sous-classe de nombre, donc float [] est une sous-classe de nombre [] numéro [] numArray = floatArray; // L'énoncé suivant lancera une exception ArrayStoreException numArray = intList.toArray (numArray);
Code 2:
List <umber> intList = new ArrayList <Nombre> (); // Le type de liste est le numéro. Mais le nombre est une classe abstraite et ne peut stocker que des instances de sa sous-classe intList.add (new Integer ()); intList.add (new Integer ()); Float [] floatArray = new float []; // float est une sous-classe de nombre, donc float [] est une sous-classe de nombre [] numéro [] numArray = floatArray; // L'instruction suivante lancera une exception ArrayStoreException numArray = intList.toArray (numArray);
Les exceptions ci-dessus sont toutes causées par ce fait: si A est la classe parent de B, alors A [] est la classe parent de B []. Toutes les classes de Java héritent de l'objet, et objet [] est la classe parent de tous les tableaux.
Ce message 8 donne un exemple, montrant que même si le type de cette méthode est déclaré comme E, la ArrayStoreException ne peut pas être évitée.
Cette exception est également mentionnée dans la documentation de cette méthode:
ArrayStoreException Si le type d'exécution du tableau spécifié n'est pas un supertype du type d'exécution de chaque élément de cette liste.
3 Il peut être compatible avec les versions avant Java 1.5
Cette méthode est apparue avant l'introduction de génériques en Java (les génériques ont été introduits dans JDK1.5). Il a été déclaré à ce moment-là:
Objet javapublic [] toarray (objet [] a)
Une fois les génériques, de nombreuses classes et méthodes deviennent génériques. Cette méthode le déclare également comme ceci:
Javapublic <t> t [] toarray (t [] a)
Cette déclaration est compatible avec les versions avant Java 1.5.
4 quelques mots supplémentaires
Cette méthode nécessite un paramètre de tableau. Si la longueur de ce tableau est supérieure ou égale à la taille de la liste actuelle, les éléments de la liste seront stockés dans le tableau; Si la longueur de ce tableau est inférieure à la taille de la liste actuelle, un nouveau tableau sera créé et les éléments de la liste actuelle seront stockés dans le tableau nouvellement créé. Pour améliorer l'efficacité, si possible, la longueur du tableau passé doit être supérieure ou égale à la taille de la liste pour éviter de créer un nouveau tableau par cette méthode.
List <Integer> intList = new ArrayList <Integer> (); intList.add (); intList.add (); // coller dans un tableau, sa longueur est numéro [] numArray = intList.toArray (nouveau numéro []); // instruction // coller dans un tableau, sa longueur est égale à la longueur du numéro intList [] numArray = intList.toArray (nouveau numéro [intList.size ()]); //Déclaration
De plus, le tableau en tant que paramètres ne peut pas être nul, sinon une nulpointerException sera lancée.
Notes de bas de page:
1
Java efficace (2e édition)
2
Lien
3
Lien
4
Lien
5
Lien
6
Lien
7
Lien
8
Lien
9
Lien
10
Lien
Créé: 2016-04-06 mer 21:14
EMACS 24.5.1 (mode ORG 8.2.10)
Valider
Le contenu ci-dessus est la raison pour laquelle le type de paramètre de la méthode Java ArrayList.ToArray (t []) vous a présenté par l'éditeur est t au lieu de E. J'espère que cela sera utile à tout le monde!