Si je me souviens bien, avant Java 8, la capacité par défaut de ArrayList
était de 10.
Étonnamment, le commentaire sur le constructeur par défaut (void) dit toujours: Constructs an empty list with an initial capacity of ten.
De ArrayList.Java
:
/**
* Shared empty array instance used for default sized empty instances. We
* distinguish this from EMPTY_ELEMENTDATA to know how much to inflate when
* first element is added.
*/
private static final Object[] DEFAULTCAPACITY_EMPTY_ELEMENTDATA = {};
...
/**
* Constructs an empty list with an initial capacity of ten.
*/
public ArrayList() {
this.elementData = DEFAULTCAPACITY_EMPTY_ELEMENTDATA;
}
Techniquement, c'est 10
, pas zéro, si vous admettez une initialisation lente 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;
Vous faites simplement référence à l'objet de tableau initial de taille zéro partagé entre tous les objets ArrayList
initialement vides. C'est à dire. la capacité de 10
est garantie lazily, une optimisation également présente dans Java 7.
Certes, le contrat de constructeur n’est pas tout à fait exact. C'est peut-être la source de confusion ici.
Voici un courriel de Mike Duigou
J'ai posté une version mise à jour du correctif vide ArrayList et HashMap.
http://cr.openjdk.Java.net/~mduigou/JDK-7143928/1/webrev/
Cette mise en œuvre révisée introduit aucun nouveau champ dans l'une ou l'autre classe. Pour ArrayList, l'allocation paresseuse du tableau de sauvegarde n'a lieu que 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. Cette optimisation sera donc valable dans la très grande majorité des cas.
Pour HashMap, le champ de seuil est utilisé de manière créative pour suivre la taille initiale demandée jusqu'à ce que le groupe de compartiments soit nécessaire. Du côté de la 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 le besoin de gonfler le tableau de compartiments. Dans readObject, il est un peu plus difficile d’essayer de choisir une capacité initiale efficace.
De: http://mail.openjdk.Java.net/pipermail/core-libs-dev/2013-April/015585.html
En Java 8, la capacité par défaut de ArrayList est 0 jusqu'à ce que nous ajoutions au moins un objet dans l'objet ArrayList (vous pouvez l'appeler initialisation différée). Veuillez consulter le code ci-dessous pour obtenir de l'aide.
ArrayList al = new ArrayList(); //Size: 0, Capacity: 0
ArrayList al = new ArrayList(5); //Size: 0, Capacity: 5
ArrayList al = new ArrayList(new ArrayList(5)); //Size: 0, Capacity: 0
al.add( "shailesh" ); //Size: 1, Capacity: 10
public static void main( String[] args )
throws Exception
{
ArrayList al = new ArrayList();
getCapacity( al );
al.add( "shailesh" );
getCapacity( al );
}
static void getCapacity( ArrayList<?> l )
throws Exception
{
Field dataField = ArrayList.class.getDeclaredField( "elementData" );
dataField.setAccessible( true );
System.out.format( "Size: %2d, Capacity: %2d%n", l.size(), ( (Object[]) dataField.get( l ) ).length );
}
Response: -
Size: 0, Capacity: 0
Size: 1, Capacity: 10
Maintenant, la question est pourquoi ce changement a été fait dans Java 8?
La réponse consiste à é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 lors de la création et les remplissons avec null .. .. Un tableau vide (rempli de nuls) occupe beaucoup de mémoire.
Une initialisation lente retarde cette consommation de mémoire jusqu'au moment où vous utiliserez réellement la liste de tableaux.
Article Capacité par défaut d'ArrayList en Java 8 l'explique en détail.
Si la toute première opération effectuée avec ArrayList consiste à transmettre à addAll
une collection comportant plus de dix éléments, toute tentative visant à créer un tableau à dix éléments destiné à contenir le contenu de ArrayList serait rejetée par la fenêtre. Chaque fois que quelque chose est ajouté à une liste de tableaux, il est nécessaire de vérifier si la taille de la liste résultante dépassera la taille du magasin de sauvegarde. Si la taille du magasin de support initial est de zéro au lieu de dix, le test échouera une fois de plus dans la durée de vie d'une liste dont la première opération est un "add", ce qui nécessiterait la création du tableau initial à dix éléments, mais ce coût est moins que le coût de la création d'un tableau de dix éléments qui ne finit jamais par être utilisé.
Cela dit, il aurait peut-être été possible d'améliorer encore les performances dans certains contextes s'il y avait eu une surcharge de "addAll" qui spécifiait le nombre d'éléments (le cas échéant) qui seraient vraisemblablement ajoutés à la liste après le présent, et qui pourraient l'utiliser pour influencer son comportement d'allocation. Dans certains cas, le code qui ajoute les derniers éléments à une liste aura une bonne idée que la liste n’aura jamais besoin d’espace supplémentaire. Il existe de nombreuses situations dans lesquelles une liste sera remplie une fois et ne sera jamais modifiée par la suite. Si le code de point sait que la taille ultime d’une liste sera de 170 éléments, elle comporte 150 éléments et un magasin de support de taille 160, augmenter le magasin de support à la taille 320 sera inutile et le laisser à la taille 320 ou le réduire au minimum. 170 sera moins efficace que le simple fait que la prochaine allocation le porte à 170.
La question est "pourquoi?".
Les inspections de profilage de la mémoire (par exemple ( https://www.yourkit.com/docs/Java/help/inspections_mem.jsp#sparse_arrays ) indiquent que les tableaux vides 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 que nous les complétons avec des valeurs NULL. Les applications Java réelles créent des millions de listes de tableaux.
La modification introduite supprime ^ W le report de la consommation de mémoire jusqu'au moment où vous utiliserez réellement la liste de tableaux.
La taille par défaut d'ArrayList dans Java 8 est égale à 10. La seule modification apportée à Java 8 est que, si un codeur ajoute des éléments inférieurs à 10, les espaces vides arraylist restants ne sont pas définis avec la valeur null. Dire cela parce que j’ai moi-même traversé cette situation et qu’Eclipse m’a fait examiner ce changement de Java 8.
Vous pouvez justifier ce changement en regardant la capture d'écran ci-dessous. Vous pouvez y voir que la taille d’ArrayList est spécifiée par 10 dans Object [10] mais que le nombre d’éléments affichés n’est que de 7. Les éléments de valeur null restants ne sont pas affichés ici. Sous Java 7, la capture d'écran ci-dessous est identique à une seule modification, à savoir que les éléments de valeur NULL sont également affichés et que le codeur doit écrire du code pour gérer les valeurs NULL s'il itère une liste complète de tableaux alors que dans Java 8, cette charge est supprimée le chef du codeur/développeur.