Java List toArray (T a) implémentation

Je regardais juste la méthode définie dans l’interface List:

Renvoie un tableau contenant tous les éléments de cette liste dans le bon ordre. le type d’exécution du tableau retourné est celui du tableau spécifié. Si la liste rentre dans le tableau spécifié, elle y est retournée. Sinon, un nouveau tableau est alloué avec le type d’exécution du tableau spécifié et la taille de cette liste. Si la liste rentre dans le tableau spécifié avec de la place pour épargner (c’est-à-dire que le tableau a plus d’éléments que la liste), l’élément du tableau qui suit immédiatement la fin de la collection est défini sur null. Ceci est utile pour déterminer la longueur de la liste uniquement si l’appelant sait que la liste ne contient aucun élément null.

 T[] toArray(T[] a); 

Et je me demandais simplement pourquoi il est implémenté de cette façon. En gros, si vous lui passez un tableau de longueur <à list.size (), il en créera simplement un nouveau et le renverra. Par conséquent, la création du nouvel objet Array dans le paramètre method est inutile.

De plus, si vous lui passez un tableau assez long en utilisant la taille de la liste si renvoie le même object avec les objects, il est inutile de le renvoyer car il s’agit du même object mais correct, par souci de clarté.

Le problème est que je pense que cela favorise un code légèrement inefficace. À mon avis, toArray devrait simplement recevoir la classe et simplement renvoyer le nouveau tableau avec le contenu.

Y a-t-il une raison pour laquelle ce n’est pas codé de cette façon?

Comme mentionné par d’autres, il y a deux raisons différentes:

  • Vous devez transmettre le type d’une manière ou d’une autre, et transmettre un tableau du type spécifié n’est pas une manière déraisonnable de le faire. Certes, il serait peut-être bien qu’il y ait une version que vous passez dans la classe du type que vous voulez aussi, pour la rapidité.
  • Si vous voulez réutiliser votre tableau, vous pouvez continuer à passer dans le même, plutôt que de devoir en créer un nouveau à chaque fois. Cela peut économiser du temps et de la mémoire, ainsi que des problèmes de GC si vous devez le faire plusieurs fois
  357 public  T[] toArray(T[] a) { 358 if (a.length < size) 359 // Make a new array of a's runtime type, but my contents: 360 return (T[]) Arrays.copyOf(elementData, size, a.getClass()); 361 System.arraycopy(elementData, 0, a, 0, size); 362 if (a.length > size) 363 a[size] = null; 364 return a; 365 } 

Peut-être alors qu’il a un type d’exécution?

De wiki:

Par conséquent, l’instanciation d’une classe Java d’un type paramétré est impossible car l’instanciation nécessite un appel à un constructeur, indisponible si le type est inconnu.

Cela vous permettra très probablement de réutiliser des tableaux. Vous éviterez ainsi l’allocation de tableaux (relativement coûteux) pour certains cas d’utilisation. Un autre avantage beaucoup moins important est que l’appelant peut instancier un tableau légèrement plus efficacement, puisque toArray () doit utiliser la méthode ‘java.lang.reflect.Array.newInstance’.

Cette méthode est une sauvegarde de Java antérieure à la 1.5. Voici le lien vers javadoc

À l’époque, c’était le seul moyen de convertir une liste en un tableau réifiable.

C’est un fait obscur, mais bien que vous puissiez stocker n’importe quoi dans le tableau Object [], vous ne pouvez pas transtyper ce tableau en un type plus spécifique, par exemple

 Object[] generic_array = { "ssortingng" }; Ssortingng[] ssortingngs_array = generic_array; // ClassCastException 

Apparemment plus efficace, List.toArray() ne fait que cela, il crée un tableau Object générique.

Avant les génériques Java, la seule façon de faire un transfert typescript consistait à avoir ce cludge:

 Ssortingng[] stronglyTypedArrayFromList ( List ssortingngs ) { return (Ssortingng[]) ssortingngs.toArray( new Ssortingng[] ); // or another variant // return (Ssortingng[]) ssortingngs.toArray( new Ssortingng[ ssortingngs.size( ) ] ); } 

Heureusement, les génériques ont rendu ce genre de machinations obsolètes. Cette méthode a été laissée là pour fournir une compatibilité ascendante avec le code pré-1.5.

Je suppose que si vous connaissez déjà le type concret de T au moment où vous appelez toArray(T[]) , il est plus performant de simplement déclarer un tableau de ce que c’est pour vous – et dans de nombreux cas, vous pouvez réutiliser le tableau.

Mais si cela vous agace, il est assez facile d’écrire une méthode utilitaire:

 public static  E[] ToArray(Collection c, Class componentType) { E[] array = (E[]) Array.newInstance(componentType, c.size()); return c.toArray(array); } 

(Notez qu’il n’y a aucun moyen d’écrire E[] ToArray(Collection c) , car il est impossible de créer un tableau de E au moment de l’exécution sans un object Class et aucun moyen d’obtenir un object Class pour E au moment de l’exécution, car les génériques ont été effacés.)