Copie Java ArrayList

214

J'ai un ArrayList l1de taille 10. J'attribue l1à un nouveau type de référence de liste l2. Will l1et l2pointer vers le même ArrayListobjet? Ou une copie de l' ArrayListobjet est-elle affectée l2?

Lorsque l2j'utilise la référence, si je mets à jour l'objet de liste, il reflète également les changements dans le l1type de référence.

Par exemple:

List<Integer> l1 = new ArrayList<Integer>();
for (int i = 1; i <= 10; i++) {
    l1.add(i);
}

List l2 = l1;
l2.clear();

N'y a-t-il pas d'autre moyen d'affecter une copie d'un objet liste à une nouvelle variable de référence, à part la création de 2 objets liste et la copie sur des collections de l'ancien vers le nouveau?

user309281
la source

Réponses:

460

Oui, l'affectation copiera simplement la valeur de l1(qui est une référence) dans l2. Ils feront tous deux référence au même objet.

La création d'une copie superficielle est assez simple cependant:

List<Integer> newList = new ArrayList<>(oldList);

(Juste un exemple.)

Jon Skeet
la source
1
Est-il possible de copier seulement une partie d'une liste d'arraylist vers une nouvelle liste d'arraylist, efficacement. par exemple: copier des éléments entre la position 5 et 10 d'un arraylist vers un autre nouveau arraylist. Dans mon application, la gamme serait beaucoup plus grande.
Ashwin
1
@Ashwin: Eh bien, c'est une opération O (N), mais oui ... vous pouvez utiliser List.subListpour obtenir une "vue" sur une section de la liste d'origine.
Jon Skeet du
que faire si les listes de tableaux sont imbriquées (ArrayList<ArrayList<Object>>)? cela créerait-il récursivement des copies de tous les objets ArrayList enfants?
Cat
3
@Cat: Non ... Ce n'est qu'une copie superficielle.
Jon Skeet
1
@ShanikaEdiriweera: Oui, vous pouvez le faire de manière fluide avec des flux. Mais la partie délicate est de créer une copie complète, que la plupart des objets ne fourniront pas. Si vous avez un cas spécifique en tête, je vous suggère de poser une nouvelle question avec des détails.
Jon Skeet
67

Essayez d'utiliser Collections.copy(destination, source);

Sergii Zagriichuk
la source
14
Voulez-vous expliquer pourquoi cela pourrait être préférable new ArrayList<>(source);?
Alex
6
@atc c'est une autre façon de faire une copie superficielle, au lieu de la nouvelle ArrayList (), il est utilisé un autre algorithme et peut être utilisé pour n'importe quelle implémentation de liste, pas seulement pour une ArrayList, c'est tout :)
Sergii Zagriichuk
14
Cette méthode est très trompeuse! En fait, sa description est. Il dit: "copie les éléments d'une liste source dans la destination", mais ils ne sont pas copiés! Ils sont référencés donc il n'y aura qu'une seule copie des objets et s'ils sont mutables, vous avez des ennuis
ACV
5
nulle part en java-api le clonage profond n'est effectué par une classe de collection
Vikash
Cette réponse n'a pas beaucoup de sens. Collections.copyn'est pas du tout une alternative à new ArrayList<>(source). Ce qui Collections.copyse passe en réalité, c'est de supposer qu'il destination.size()est au moins aussi grand que source.size(), puis copiez la plage index par index à l'aide de la set(int,E)méthode. La méthode n'a pas ajouter de nouveaux éléments à la destination. Reportez-vous au code source s'il n'est pas suffisamment clair à partir de Javadoc.
Radiodef
35

Oui l1et l2pointera vers la même référence, le même objet.

Si vous souhaitez créer une nouvelle liste de tableaux basée sur l'autre liste de tableaux, procédez comme suit:

List<String> l1 = new ArrayList<String>();
l1.add("Hello");
l1.add("World");
List<String> l2 = new ArrayList<String>(l1); //A new arrayList.
l2.add("Everybody");

Le résultat sera l1aura toujours 2 éléments et l2aura 3 éléments.

Alfredo Osorio
la source
Pouvez-vous expliquer la différence entre List<String> l2 = new ArrayList<String>(l1)et List<String> l2 = l1?
MortalMan du
@MortalMan la différence est que l2 = new ArrayList <String> (l1) est un objet entièrement nouveau et la modification de l2 n'affecte pas l1, alors que List <String> l2 = l1 vous ne créez pas un nouvel objet mais vous y faites simplement référence comme l1, dans ce cas, effectuer une opération telle que l2.add ("Tout le monde"), l1.size () et l2.size () renverra 3 car les deux font référence au même objet.
Alfredo Osorio
19

Un autre moyen pratique de copier les valeurs de src ArrayList vers dest Arraylist est le suivant:

ArrayList<String> src = new ArrayList<String>();
src.add("test string1");
src.add("test string2");
ArrayList<String> dest= new ArrayList<String>();
dest.addAll(src);

Il s'agit d'une copie réelle de valeurs et pas seulement d'une copie de référence.

Harshal Waghmare
la source
10
je ne suis pas tout à fait sûr que ce soit exact. mon test montre le contraire (faisant toujours référence au même objet)
invertigo
cette solution a fonctionné pour moi lors de l'utilisation d'ArrayList avec ArrayAdapter
albanx
1
Cette réponse est fausse. addAll () copie simplement les références comme l'a dit invertigo. Ce n'est pas une copie complète.
jk7
Pour une ArrayList <String>, cette réponse est acceptable car String est immuable, mais essayez-la avec l'exemple de l'OP, une ArraList <Integer>, et vous verrez qu'il s'agit simplement de copier des références.
jk7
Ce n'est pas ma journée, je suppose. Il s'avère que des classes telles que Integer et Long sont également immuables, donc la réponse de Harshal fonctionne pour des cas simples tels que ArrayList <Integer> et ArrayList <String>. Là où il échoue, c'est pour des objets complexes qui ne sont pas immuables.
jk7
8

Il existe une méthode addAll () qui servira à copier un ArrayList dans un autre.

Par exemple, vous avez deux listes de tableaux : sourceList et targetList , utilisez le code ci-dessous.

targetList.addAll (sourceList);

vaibhav agrawal
la source
il copie également simplement les références.
Vikash
4

Java ne transmet pas d'objets, il transmet des références (pointeurs) aux objets. Alors oui, l2 et l1 sont deux pointeurs vers le même objet.

Vous devez faire une copie explicite si vous avez besoin de deux listes différentes avec le même contenu.

JB Nizet
la source
3
Comment faites-vous "une copie explicite"? Je suppose que vous parlez d'une copie complète?
Cin316
1

List.copyOf List liste non modifiable

Tu as demandé:

N'y a-t-il pas d'autre moyen d'attribuer une copie d'une liste

Java 9 a apporté les List.ofméthodes d'utilisation des littéraux pour créer une Listclasse concrète inconnue et non modifiable .

LocalDate today = LocalDate.now( ZoneId.of( "Africa/Tunis" ) ) ;
List< LocalDate > dates = List.of( 
    today.minusDays( 1 ) ,  // Yesterday
    today ,                 // Today
    today.plusDays( 1 )     // Tomorrow
);

Parallèlement à cela, nous avons également obtenu List.copyOf. Cette méthode renvoie également une Listclasse concrète inconnue et non modifiable .

List< String > colors = new ArrayList<>( 4 ) ;          // Creates a modifiable `List`. 
colors.add ( "AliceBlue" ) ;
colors.add ( "PapayaWhip" ) ;
colors.add ( "Chartreuse" ) ;
colors.add ( "DarkSlateGray" ) ;
List< String > masterColors = List.copyOf( colors ) ;   // Creates an unmodifiable `List`.

Par «non modifiable», nous entendons le nombre d'éléments dans la liste, et le référent objet tenu dans chaque emplacement comme élément, est fixe. Vous ne pouvez pas ajouter, supprimer ou remplacer des éléments. Mais le référent objet contenu dans chaque élément peut ou non être mutable .

colors.remove( 2 ) ;          // SUCCEEDS. 
masterColors.remove( 2 ) ;    // FAIL - ERROR.

Découvrez ce code en direct sur IdeOne.com .

dates.toString (): [2020-02-02, 2020-02-03, 2020-02-04]

colours.toString (): [AliceBlue, PapayaWhip, DarkSlateGray]

masterColors.toString (): [AliceBlue, PapayaWhip, Chartreuse, DarkSlateGray]

Vous avez posé des questions sur les références d'objets. Comme d'autres l'ont dit, si vous créez une liste et l'affectez à deux variables de référence (pointeurs), vous n'avez toujours qu'une seule liste. Les deux pointent vers la même liste. Si vous utilisez l'un ou l'autre pointeur pour modifier la liste, les deux pointeurs verront ultérieurement les modifications, car il n'y a qu'une seule liste en mémoire.

Vous devez donc faire une copie de la liste. Si vous souhaitez que cette copie ne soit pas modifiable, utilisez la List.copyOfméthode décrite dans cette réponse. Dans cette approche, vous vous retrouvez avec deux listes distinctes, chacune avec des éléments qui contiennent une référence aux mêmes objets de contenu. Par exemple, dans notre exemple ci-dessus utilisant des Stringobjets pour représenter des couleurs, les objets de couleur flottent quelque part en mémoire. Les deux listes contiennent des pointeurs vers les mêmes objets de couleur. Voici un schéma.

entrez la description de l'image ici

La première liste colorsest modifiable. Cela signifie que certains éléments pourraient être supprimés comme indiqué dans le code ci-dessus, où nous avons supprimé le 3e élément d'origine Chartreuse(index de 2 = ordinal 3). Et des éléments peuvent être ajoutés. Et les éléments peuvent être modifiés pour pointer vers d'autres Stringtels que OliveDrabou CornflowerBlue.

En revanche, les quatre éléments de masterColorssont fixes. Aucun retrait, aucun ajout et aucun remplacement d'une autre couleur. Cette Listimplémentation n'est pas modifiable.

Basil Bourque
la source