web-dev-qa-db-fra.com

clone (): ArrayList.clone () Je pensais faire une copie superficielle

ArrayList<Integer> a=new ArrayList<Integer>();
a.add(5);
ArrayList<Integer> b=(ArrayList<Integer>)a.clone();
a.add(6);
System.out.println(b.toString());

Dans le morceau de code ci-dessus, je pense que clone() fait une copie superficielle. Ainsi, b et a doivent pointer vers le même emplacement mémoire. Cependant, quand je fais b.toString(), la réponse est seulement 5. Pourquoi 6 N'est-il pas également affiché si clone() fait une copie superficielle?

20
TimeToCodeTheRoad

Une copie superficielle ne signifie pas qu'ils pointent vers le même emplacement mémoire. Ce ne serait qu'une affectation: List b = a;.

Le clonage crée une nouvelle instance, contenant les mêmes éléments . Cela signifie que vous avez 2 listes différentes, mais leur contenu est le même. Si vous changez l'état d'un objet dans la première liste, il changera dans la deuxième liste. (Puisque vous utilisez un type immuable - Integer - vous ne pouvez pas observer cela)

Cependant, vous devriez envisager de ne pas utiliser clone(). Cela fonctionne bien avec les collections, mais généralement il est considéré comme cassé. Utilisez les constructeurs de copie - new ArrayList(originalList)

50
Bozho

Si elle était comme vous le pensiez, alors la méthode clone le ferait serait complètement inutile, car dans ce cas, les lignes suivantes seraient équivalentes:

ArrayList<Integer> b = (ArrayList<Integer>)a.clone();
ArrayList<Integer> b = a;

Le clonage est - comme dans les scénarios du monde réel - un processus de création de deux entités ayant exactement les mêmes propriétés (au moment de l'opération de clonage).

Et comme Bozho l'a mentionné - évitez le concept Java clone(). Même son auteur l'a mentionné, il est cassé.

Cette question et ses réponses sont très utiles et fournissent un lien vers les propres commentaires de Josh Blochs sur son travail ;-)

6
Andreas_D

Cela fait en effet une copie superficielle, voici un commentaire pour clone, à partir du code source d'ArrayList

Renvoie une copie superficielle de cette instance ArrayList. (Les éléments eux-mêmes ne sont pas copiés.)

Pour comprendre cela, regardons un extrait de code dans la méthode de clonage de ArrayList

v.elementData = Arrays.copyOf(elementData, size);

Comme nous le savons, lorsque nous affectons un objet à une variable, Java ne fait pas une toute nouvelle copie de cet objet. Au lieu de cela, cette variable devient une autre référence pointant vers l'objet d'origine.

Ainsi, elementData stocke en fait une référence aux objets placés dans cette liste de tableaux. Et il suffit de copier ces références, aucune réplique d'objets n'est créée.

Bien sûr, vous pouvez supprimer ou ajouter une nouvelle référence à une liste de tableaux clonée.

Cependant, la modification d'anciens objets dans une ArrayList affectera la ArrayList d'origine. Il est difficile de faire une illustration avec votre exemple car Integer est immuable.

Pour voir l'effet secondaire, vous pouvez définir un objet mutable personnalisé

class Person {
        private int a;

        public void setA(int a) {
            this.a = a;
        }
        public int getA() {
            return a;
        }
        @Override
        public String toString() {
            return String.valueOf(a);
        } 
   } 

Ensuite, vous pouvez utiliser le code suivant pour effectuer le test

        Person p1 = new Person();
        Person p2 = new Person();

        ArrayList<Person> tt = new ArrayList<Person>();
        tt.add(p1);
        tt.add(p2);

        ArrayList<Person> yy = (ArrayList<Person>) tt.clone();
        Person vv = yy.get(yy.indexOf(p2));
        vv.setA(12);
        yy.remove(p1);

        System.out.println("tt: " + tt);
        System.out.println("yy: " +yy);

La sortie doit être

tt: [0, 12]
aa: [12]

Voir l'effet secondaire :)? Nous modifions uniquement l'élément en yy, mais il se reflète également dans tt.

1
user2473519

Le clonage superficiel est la stratégie de clonage par défaut fournie par Object.clone() dont vous parlez. La méthode clone() de la classe d'objets crée une nouvelle instance et copie tous les champs de l'objet Cloneable dans cette nouvelle instance (soit primitive, soit référence). Ainsi, dans le cas des types de référence, seuls les bits de référence sont copiés dans la nouvelle instance, par conséquent, la variable de référence des deux objets pointera vers le même objet. L'exemple que nous avons vu ci-dessus est un exemple de clonage superficiel.

Clonage profond Comme son nom l'indique, le clonage profond signifie tout cloner d'un objet à un autre. Pour y parvenir, nous devons tromper notre méthode clone() pour fournir notre propre stratégie de clonage. Nous pouvons le faire en implémentant l'interface Cloneable et en remplaçant la méthode clone () dans tous les types de référence que nous avons dans notre hiérarchie d'objets, puis appelons super.clone() et ces méthodes clone() dans la méthode de clonage de notre objet.

Mais si vous regardez la méthode clone () d'ArrayList dans le code source, vous verrez qu'elle copie en externe v.elementData = Arrays.copyOf(elementData, size); après avoir appelé super.clone(), ce qui signifie que clone () d'ArrayList copie en profondeur il contenu

public Object clone() {
    try {
        ArrayList<?> v = (ArrayList<?>) super.clone();
        v.elementData = Arrays.copyOf(elementData, size);
        v.modCount = 0;
        return v;
    } catch (CloneNotSupportedException e) {
        // this shouldn't happen, since we are Cloneable
        throw new InternalError(e);
    }
}

Pour en savoir plus sur le clonage et ses types comme le clonage profond et le clonage superficiel, veuillez lire Clonage Java et types de clonage (peu profond et profond) dans les détails avec l'exemple

1
Naresh Joshi

la fonction de clonage dans Arraylist n'est pas la même chose que la copie d'un arraylist à un autre, si nous utilisons clone (), il contient la copie de l'arraylist d'origine, mais si nous apportons des modifications à l'arraylist d'origine après utilisation de clone (), cela n'affectera pas la arraylist copié .. Par exemple:

public static void main(String[] a) {

List list = new ArrayList();

list.add("A");

List list2 = ((List) ((ArrayList) list).clone());

System.out.println(list);
System.out.println(list2);

list.clear();

System.out.println(list);
System.out.println(list2);
}

Production:-

[UNE]

[UNE]

[]

[UNE]

0
Dahlia

ne pouvons-nous pas sélectionner dynamiquement à quelle position nous voulons ajouter la chaîne comme celle-ci

int r=k.nextInt();
Integer i6=new Integer(r);
System.out.println("Enter the address");
String p6=k.nextLine();
ar3.add(i6,p6);

ce n'est pas excuter après avoir lu l'entier

0
vijay