Techniquement, ce n'est 10
pas zéro si vous admettez une initialisation paresseuse du tableau de sauvegarde. Voir:
public boolean add(E e) {
ensureCapacityInternal(size + 1);
elementData[size++] = e;
return true;
}
private void ensureCapacityInternal(int minCapacity) {
if (elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA) {
minCapacity = Math.max(DEFAULT_CAPACITY, minCapacity);
}
ensureExplicitCapacity(minCapacity);
}
où
/**
* Default initial capacity.
*/
private static final int DEFAULT_CAPACITY = 10;
Ce à quoi vous faites référence est simplement l'objet de tableau initial de taille zéro qui est partagé entre tous les ArrayList
objets initialement vides . C'est-à-dire que la capacité de 10
est garantie paresseusement , une optimisation qui est également présente dans Java 7.
Certes, le contrat constructeur n'est pas entièrement exact. C'est peut-être là une source de confusion.
Contexte
Voici un e-mail de Mike Duigou
J'ai publié une version mise à jour du patch vide ArrayList et HashMap.
http://cr.openjdk.java.net/~mduigou/JDK-7143928/1/webrev/
Cette implémentation révisée n'introduit aucun nouveau champ dans aucune des classes. Pour ArrayList, l'allocation différée du tableau de sauvegarde se produit uniquement si la liste est créée à la taille par défaut. Selon notre équipe d'analyse des performances, environ 85% des instances ArrayList sont créées à la taille par défaut, donc cette optimisation sera valide pour une majorité écrasante de cas.
Pour HashMap, la création utilise le champ de seuil pour suivre la taille initiale demandée jusqu'à ce que le tableau de bucket soit nécessaire. Du côté lecture, le cas de la carte vide est testé avec isEmpty (). Sur la taille d'écriture, une comparaison de (table == EMPTY_TABLE) est utilisée pour détecter la nécessité de gonfler le tableau de compartiment. Dans readObject, il y a un peu plus de travail pour essayer de choisir une capacité initiale efficace.
De: http://mail.openjdk.java.net/pipermail/core-libs-dev/2013-April/015585.html
getCapacity()
méthode, ou quelque chose comme ça. (Cela dit, quelque chose commeensureCapacity(7)
un no-op pour une ArrayList initialisée par défaut, donc je suppose que nous sommes vraiment censés agir comme si sa capacité initiale était vraiment de 10ArrayList
création avec le constructeur no-arg vs en passant zéro auint
constructeur, et si vous examinez la taille du tableau interne de manière réfléchie ou dans un débogueur. Dans le cas par défaut, le tableau passe de la longueur 0 à 10, puis à 15, 22, suivant le taux de croissance de 1,5x. Passer à zéro comme capacité initiale entraîne une croissance de 0 à 1, 2, 3, 4, 6, 9, 13, 19 ....emptyList()
consomme toujours moins de mémoire que plusieursArrayList
instances vides . C'est juste moins important maintenant et donc pas nécessaire à chaque endroit, surtout pas aux endroits avec une probabilité plus élevée d'ajouter des éléments plus tard. Gardez également à l'esprit que vous voulez parfois une liste vide immuable et queemptyList()
c'est la voie à suivre.Dans java 8, la capacité par défaut d'ArrayList est de 0 jusqu'à ce que nous ajoutions au moins un objet dans l'objet ArrayList (vous pouvez l'appeler initialisation paresseuse).
Maintenant, la question est de savoir pourquoi ce changement a été effectué dans JAVA 8?
La réponse est d'économiser la consommation de mémoire. Des millions d'objets de liste de tableaux sont créés dans des applications Java en temps réel. La taille par défaut de 10 objets signifie que nous allouons 10 pointeurs (40 ou 80 octets) pour le tableau sous-jacent à la création et les remplissons avec des valeurs nulles. Un tableau vide (rempli de valeurs nulles) occupe beaucoup de mémoire.
L'initialisation différée reporte cette consommation de mémoire jusqu'au moment où vous utiliserez réellement la liste des tableaux.
Veuillez consulter le code ci-dessous pour obtenir de l'aide.
Article La capacité par défaut de ArrayList dans Java 8 l' explique en détail.
la source
Si la toute première opération effectuée avec un ArrayList consiste à transmettre
addAll
une collection qui a plus de dix éléments, alors tout effort mis dans la création d'un tableau initial de dix éléments pour contenir le contenu de ArrayList serait rejeté par la fenêtre. Chaque fois que quelque chose est ajouté à une ArrayList, il est nécessaire de tester si la taille de la liste résultante dépassera la taille du magasin de sauvegarde; autoriser le magasin de stockage initial à avoir une taille de zéro au lieu de dix entraînera l'échec de ce test une fois de plus dans la durée de vie d'une liste dont la première opération est un "ajout" qui nécessiterait la création du tableau initial de dix éléments, mais ce coût est moins que le coût de création d'un tableau de dix éléments qui ne finit jamais par être utilisé.Cela dit, il aurait pu être possible d'améliorer encore les performances dans certains contextes s'il y avait une surcharge de "addAll" qui spécifiait combien d'éléments (le cas échéant) seraient probablement ajoutés à la liste après la liste actuelle, et lesquels pourraient utilisez cela pour influencer son comportement d'allocation. Dans certains cas, le code qui ajoute les derniers éléments à une liste aura une assez bonne idée que la liste n'aura jamais besoin d'espace au-delà de cela. Il existe de nombreuses situations où une liste sera remplie une fois et ne sera jamais modifiée par la suite. Si au point code sait que la taille ultime d'une liste sera de 170 éléments, elle comporte 150 éléments et un magasin de sauvegarde de taille 160,
la source
addAll()
. C'est encore une autre opportunité d'améliorer l'efficacité autour du premier malloc.La question est «pourquoi?».
Inspections de profilage de la mémoire (par exemple ( https://www.yourkit.com/docs/java/help/inspections_mem.jsp#sparse_arrays ) montrent que les tableaux vides (remplis de valeurs nulles) occupent des tonnes de mémoire.
La taille par défaut de 10 objets signifie que nous allouons 10 pointeurs (40 ou 80 octets) pour le tableau sous-jacent à la création et les remplissons avec des valeurs nulles. Les vraies applications Java créent des millions de listes de baies.
La modification introduite supprime ^ W reporter cette consommation de mémoire jusqu'au moment où vous utiliserez réellement la liste des tableaux.
la source
Après la question ci-dessus, j'ai parcouru le document ArrayList de Java 8. J'ai trouvé que la taille par défaut est toujours de 10 seulement.
la source
La taille par défaut de ArrayList dans JAVA 8 est stil 10. La seule modification apportée à JAVA 8 est que si un codeur ajoute des éléments inférieurs à 10, les espaces vides de la liste de tableaux restants ne sont pas spécifiés à null. Le dire parce que j'ai moi-même traversé cette situation et que l'éclipse m'a fait examiner ce changement de JAVA 8.
Vous pouvez justifier ce changement en regardant la capture d'écran ci-dessous. Dans celui-ci, vous pouvez voir que la taille ArrayList est spécifiée comme 10 dans Object [10] mais le nombre d'éléments affichés n'est que de 7. Les éléments restants à valeur nulle ne sont pas affichés ici. Dans JAVA 7, la capture d'écran ci-dessous est la même avec un seul changement, à savoir que les éléments de valeur nulle sont également affichés pour lesquels le codeur doit écrire du code pour gérer les valeurs nulles s'il itère la liste complète des tableaux tandis que dans JAVA 8, cette charge est supprimée le chef du codeur / développeur.
Lien de capture d'écran.
la source