概述
在查看ArrayList和LinkedList的源码的时候,比较困惑的就是clone()方法。
我们都知道在Object里clone()方法是浅拷贝(浅拷贝的定义:只clone对象本身,不clone对象里的字段),那在集合里它到底是深拷贝还是浅拷贝呢?
我们看一下ArrayList.clone()源码:
public Object clone() {
try {
@SuppressWarnings("unchecked")
ArrayList<E> v = (ArrayList<E>) 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<Node> list = new ArrayList<Node>();
list.add(ins.new Node(2));
list.add(ins.new Node(11));
list.add(ins.new Node(44));
ArrayList<Node> newlist = (ArrayList<Node>) 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和newlist其实指向同一个对象呢?
执行System.out.println("list==newlist?:"+(list==newlist));
其结果为:list==newlist?:false
说明list和newlist指向两个不同的内存地址空间
同样的,LinkedList的clone()也是实现一个浅复制
1011 /**
1012 * 父类克隆方法
1013 */
1014 @SuppressWarnings("unchecked")
1015 private LinkedList<E> superClone() {
1016 try {
1017 return (LinkedList<E>) 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<E> clone = superClone();
1030
1031 // 链表初始化
1032 clone.first = clone.last = null;
1033 clone.size = 0;
1034 clone.modCount = 0;
1035
1036 // 插入结点
1037 for (Node<E> 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<Node> list = new ArrayList<Node>();
list.add(ins.new Node(2));
list.add(ins.new Node(11));
list.add(ins.new Node(44));
//深拷贝
ArrayList<Node> 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]]