web-dev-qa-db-fra.com

Distinction entre la capacité d'une liste de tableaux et la taille d'un tableau

J'ai lu l'extrait ci-dessous dans Core Java I book.

Allouer une liste de tableaux comme suit: new ArrayList <'Employee> (100) // a une capacité de 100

n’est pas la même chose que l’allocation d’un nouveau tableau sous la forme new Employee [100] // size is 100

Il existe une distinction importante entre la capacité d'une liste de tableaux et la taille d'un tableau . Si vous allouez un tableau de 100 entrées, le tableau a 100 emplacements prêts à être utilisés. Une liste de tableaux d’une capacité de 100 éléments peut contenir 100 éléments (et Dans fait, plus de 100, au prix de réallocations supplémentaires); mais au début, même après sa construction initiale, une liste de tableaux ne contient aucun élément.

Lorsque j'ai vu la liste de tableaux de code source, le constructeur a créé un tableau d'objets de capacité donnée, prêt à contenir des éléments de capacité donnée (ci-dessous, l'extrait de code). 

public ArrayList(int initialCapacity) {
     super();
     if (initialCapacity < 0)
         throw new IllegalArgumentException("Illegal Capacity: "+
                                            initialCapacity);
     this.elementData = new Object[initialCapacity];
 }

Je ne suis pas en mesure de comprendre la différence réelle de ce que l'auteur a mentionné dans le texte ci-dessus. 

14
Kumar V

Si vous allouez un nouveau tableau avec arr = new Employee[100], la taille de ce tableau (arr.length) sera de 100. Il contient 100 éléments. Tous les éléments sont initialement nuls (il s’agit d’un tableau de références d’objet), mais il existe tout de même 100 éléments.

Si vous faites quelque chose comme list = new ArrayList <Employee>(100) et essayez de vérifier list.size(), vous obtiendrez 0. Il n'y a aucun élément dans la liste.

En interne, il est vrai que ArrayList alloue suffisamment de place pour placer 100 éléments avant d’augmenter sa capacité, mais il s’agit d’un détail de mise en œuvre interne et la liste vous présente son contenu comme "aucun élément stocké". Si vous avez réellement list.add(something), vous aurez des éléments dans la liste.

Ainsi, bien que la liste alloue le stockage à l’avance, l’API avec laquelle elle communique avec le programme vous indique qu’elle ne contient aucun élément. Les éléments nuls de son tableau interne ne sont pas disponibles - vous ne pouvez pas les récupérer ni les modifier.

26
RealSkeptic

Une ArrayList n'est qu'un moyen de représenter une liste abstraite, et sa capacité est un détail de la mise en œuvre de la façon dont le système implémente la liste logique.

Un ArrayList stocke les éléments d'une liste en utilisant un tableau réel "sous les couvertures". La réalisation réelle de la matrice en mémoire d'ordinateur a une certaine taille lorsqu'elle est allouée; cette taille est la capacité de ArrayList. ArrayList émule une liste de taille variable en stockant la longueur logique de la liste en plus du tableau de longueur fixe. Ainsi, si vous avez une ArrayList d’une capacité 10 contenant 4 éléments logiques, elle peut être représentée sous la forme d’une longueur et d’un tableau.

(4) | e1 | e2 | e3 | e4 | __ | __ | __ | __ | __ | __ |

où (4) est la longueur logique de la liste et '__' représente des données ignorées car elles ne font pas partie de la liste logique. Si vous essayez d'accéder au 5ème élément de cet ArrayList, une exception sera levée car il sait que le cinquième élément n'a pas été initialisé. Si nous ajoutons ensuite un élément supplémentaire e5 à la liste, le ArrayList devient

(5) | e1 | e2 | e3 | e4 | e5 | __ | __ | __ | __ | __ |

Notez que la capacité n'a pas changé, contrairement à la longueur logique, car le tableau sous-jacent est toujours capable de gérer toutes les données de la liste logique.

Si vous parvenez à ajouter plus de dix éléments à cette liste, la liste de tableaux ne sera pas endommagée. ArrayList est une abstraction censée être compatible avec toutes les opérations de tableau. Au lieu de cela, ArrayList change de capacité lorsque sa longueur logique dépasse sa capacité d'origine. Si nous devions ajouter les éléments (a1, a2, ..., a7) à la liste ci-dessus, la liste de tableaux résultante pourrait ressembler à

(12) | e1 | e2 | e3 | e4 | e5 | a1 | a2 | a3 | a4 | a5 | a6 | a7 | __ | __ | __ | __ | __ | __ | __ | __ |

avec une capacité de 20.

Une fois que vous avez créé une liste de tableaux, vous pouvez ignorer la capacité de toute la programmation qui suit. la logique n'est pas affectée. Toutefois, les performances du système dans certains types d’opérations peuvent être affectées. L'augmentation de la capacité, par exemple, pourrait bien impliquer l'allocation d'un tableau plus grand, la copie du premier tableau dans le second, puis l'exécution des opérations. Cela peut être assez lent comparé à, par exemple la même opération sur une liste chaînée. Il est donc judicieux de choisir que la capacité d’un ArrayList soit supérieure ou du moins comparable au nombre réel d’éléments attendus dans l’environnement d’exécution réel.

7
James Hart

Cela semble mal rédigé et potentiellement incorrect si je ne le comprends pas correctement.

Je crois que ce qu’il essaie de dire est qu’il existe une différence entre la capacité initiale de ArrayList et la taille initiale de ArrayList.

List<Employee> employees = new ArrayList<>(100);
int size = employes.size();

taille sera 0 alors que la capacité initiale est 100.

Vous avez raison de lire le code source.

2
Reid Harrison

La différence est entre un conteneur taille fixe (structure de données) et un conteneur taille variable.

Un array est un conteneur fixed size. Le nombre d'éléments qu'il contient est établi lors de la création du tableau et ne change jamais. (Lorsque le tableau est créé, tous ces éléments auront une valeur par défaut, par exemple, null pour les types de référence ou 0 pour les entiers, mais ils figureront tous dans le tableau: vous pouvez les indexer tous.)

Un list est un conteneur variable size. Le nombre d'éléments qu'il contient peut varier, allant de 0 à autant que vous le souhaitez (sous réserve des limites d'implémentation). Après la création, le nombre d’éléments peut augmenter ou diminuer. Vous pouvez à tout moment récupérer n'importe quel élément par son index.

Mais le concept Java List est en réalité une interface et peut être implémenté de différentes manières. Ainsi, ArrayList, LinkedList, etc. Il existe une structure de données "derrière" la liste pour contenir les éléments. Et cette structure de données elle-même peut avoir une taille fixe ou une taille variable et, à tout moment, peut avoir la taille exacte du nombre d'éléments de la liste, ou peut-être un espace extra "tampon".

La variable LinkedList, par exemple, a toujours dans sa structure de données sous-jacente exactement le même nombre de "emplacements pour les éléments" que dans la liste qu'il représente. Mais la ArrayList utilise un tableau de longueur fixe comme magasin de sauvegarde.

Pour ArrayList, le nombre d'éléments de la liste peut être différent du nombre d'éléments que le tableau derrière peut contenir. Ces espaces "extra" pour les éléments ne contiennent que des zéros, des zéros ou autre chose, mais la variable ArrayList ne vous donne jamais accès à ces espaces. Lorsque vous ajoutez des éléments à la variable ArrayList, ils occupent plus de place dans le tableau sous-jacent, jusqu'à ce que le tableau sous-jacent soit enfin saturé. L'élément next que vous ajoutez à la ArrayList provoque l'allocation d'un tout nouveau tableau de taille fixe, légèrement supérieur au tableau "actuel", et de la copie de tous les éléments de la liste (le tableau d'origine est ignoré). Pour éviter que cette opération coûteuse (allocation et copie) ne se produise trop souvent, le nouveau tableau est plus grand que le tableau actuel (de quelques facteurs) et comporte donc des éléments qui ne conserveront pas à ce moment des éléments de la liste - ils sont vides (null ou 0).

Ainsi, comme il existe (potentiellement) une différence entre le nombre d'éléments de la liste représentée et le nombre d'éléments que la structure de données en implémentation peut contenir, il y a deux concepts en vigueur.

La taille} de la liste est le nombre d'éléments qu'elle contient. La capacité de la liste est le nombre d'éléments que la structure de données de sauvegarde peut contenir à l'heure actuelle /. La taille changera à mesure que des éléments sont ajoutés ou supprimés de la liste. La capacité changera lorsque l'implémentation de la liste que vous utilisez en a besoin. (La taille, bien sûr, ne sera jamais plus grande que la capacité.)

(BTW, pour les conteneurs de taille fixe, la taille est fréquemment appelée longueur, les tableaux ont donc une propriété longueur et les chaînes ont une méthode longueur (). les langues - parfois même la même langue - utilisent "taille" et "longueur" de manière incohérente, mais elles signifient toujours taille, et le terme "capacité" est toujours utilisé pour la taille/longueur de la structure de données sous-jacente. )

1
davidbak

Utilisons un exemple concret. Prenons un autobus de 18 places assises, d’une capacité de 18 passagers. La taille des passagers à un moment donné peut être inférieure à dix-huit, mais pas supérieure à. Lorsque le nombre de passagers est de dix-huit, aucun autre passager ne peut être accueilli.

Dans une ArrayList, la capacité a quelque chose en commun avec celle de notre bus en ce sens qu'elle définit le nombre d'éléments pouvant être insérés. Cependant, contrairement à notre bus, la capacité augmente pour accueillir le nombre d'éléments jusqu'à Integer.MAX_VALUE.

Il en va de même pour la taille, tout comme pour notre bus, la taille des éléments de la liste ne peut dépasser la capacité. Imaginez que 50 passagers voyagent dans un bus de 18 places! Tu ne veux vraiment pas être dans ce bus.

0
X09