List的clone()方法

概述

在查看ArrayList和LinkedList的源码的时候,比较困惑的就是clone()方法。
我们都知道在Object里clone()方法是浅拷贝(浅拷贝的定义:只clone对象本身,不clone对象里的字段),那在集合里它到底是深拷贝还是浅拷贝呢?
我们看一下ArrayList.clone()源码:

public Object clone() {
            try {
                @SuppressWarnings("unchecked")
                    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();
            }
        }

我们可以看到,返回的是一个全新的ArrayList实例对象,但是其elementData,也就是存储数据的数组,存储的对象还是指向了旧的ArrayList存储的那些对象。也就是ArrayList这个类实现了深拷贝,但是存储的对象还是浅拷贝。
我们验证一下:

import java.util.ArrayList;
import java.util.Iterator;

public class Main {

    static Main ins = new Main();

    //内部类
    class Node{
        int val;
        Node(int val){
            this.val = val;
        }

        public void setVal(int val) {
            this.val = val;
        }

        @Override
        public String toString() {
            return "Node [val=" + val + "]";
        }

    }

    public static void main(String[] args) {


        ArrayList list = new ArrayList();
        list.add(ins.new Node(2));
        list.add(ins.new Node(11));
        list.add(ins.new Node(44));

        ArrayList newlist = (ArrayList) list.clone();

        //修改list中元素之前的newlist
        for(Node k : newlist){
            System.out.println(k);
        }
        //修改list中index为0的对象的值为90
        list.get(0).setVal(90);
        System.out.println("--------------------------------");

        //修改后newlist,index为0的对象也变化了
        for(Node k : newlist){
            System.out.println(k);
        }
    }
}

其运行结果为:

Node [val=2]
Node [val=11]
Node [val=44]
--------------------------------
Node [val=90]
Node [val=11]
Node [val=44]

我们可以看到,通过改变旧的list存储的对象的值,新的list存储的对象的值也发生了改变。说明其指向了同一个对象。
List的clone()方法_第1张图片

那么会不会list和newlist其实指向同一个对象呢?
执行System.out.println("list==newlist?:"+(list==newlist));
其结果为:list==newlist?:false
说明list和newlist指向两个不同的内存地址空间

同样的,LinkedList的clone()也是实现一个浅复制

1011     /**
1012      * 父类克隆方法
1013      */
1014     @SuppressWarnings("unchecked")
1015     private LinkedList superClone() {
1016         try {
1017             return (LinkedList) super.clone();
1018         } catch (CloneNotSupportedException e) {
1019             throw new InternalError(e);
1020         }
1021     }
1022 
1023     /**
1024      * 克隆,浅拷贝
1025      *
1026      * @return a shallow copy of this {@code LinkedList} instance
1027      */
1028     public Object clone() {
1029         LinkedList clone = superClone();
1030 
1031         // 链表初始化
1032         clone.first = clone.last = null;
1033         clone.size = 0;
1034         clone.modCount = 0;
1035 
1036         // 插入结点
1037         for (Node x = first; x != null; x = x.next)
1038             clone.add(x.item);
1039         // 返回克隆后的对象引用
1040         return clone;
1041     }

那么要怎么实现一个ArrayList的深拷贝呢?
通过实现对象类的clone方法。

import java.util.ArrayList;
import java.util.Iterator;

public class Main {

    static Main ins = new Main();
    class Node{
        int val;
        Node(int val){
            this.val = val;
        }

        public void setVal(int val) {
            this.val = val;
        }

        @Override
        public String toString() {
            return "Node [val=" + val + "]";
        }
        //在对象中重写clone()方法
        @Override
        public Node clone(){
            Node node = new Node(this.val);
            return node;
        }
    }

    public static void main(String[] args) {
        // TODO Auto-generated method stub

        ArrayList list = new ArrayList();
        list.add(ins.new Node(2));
        list.add(ins.new Node(11));
        list.add(ins.new Node(44));

        //深拷贝
        ArrayList listCopy = new ArrayList<>();
        for(Node node:list){
            listCopy.add(node.clone());
        }
        //移除且不修改
        listCopy.get(0).setVal(100);
        System.out.println(list);
        System.out.println(listCopy);

    }
}

结果为:

[Node [val=2], Node [val=11], Node [val=44]]
[Node [val=100], Node [val=11], Node [val=44]]

你可能感兴趣的:(java)