今天学习ArrayList
一,浅复制
它的复制构造函数和clone()函数均为浅复制(shallow copy),即复制对象的引用。相反的深复制,则是复制对象的本身。
1,复制构造函数 ArrayList (Collection<? extends E> c)
得到了一个新的ArrayList对象,它包含了对c中元素的复制。但是注意,集合c的元素本质是引用,而不是对象。被引用的对象本身并没有被复制。
2,clone()函数也是如此
例子:
ArrayList<StringBuffer> temp1=new ArrayList<StringBuffer>(); StringBuffer x=new StringBuffer("yes"); temp1.add(x); ArrayList<StringBuffer> temp2=(ArrayList)temp1.clone(); temp2.set(0,x.append("no"));
但是
ArrayList<String> temp1=new ArrayList(); String x="yes";temp1.add(x);ArrayList<String> temp2=(ArrayList)temp1.clone(); temp2.set(0,"no");
3, java.util.list.addAll()方法同样是浅复制
4,下边这个遍历list逐个元素add的方法也是浅复制,这个比较容易搞错
class Person implements Serializable{ private int age; private String name; public Person(){}; public Person(int age,String name){ this.age=age; this.name=name; } public int getAge() { return age; } public void setAge(int age) { this.age = age; } public String getName() { return name; } public void setName(String name) { this.name = name; } public String toString(){ return this.name+"-->"+this.age; } }
List<Person> destList=new ArrayList<Person>(srcList.size()); for(Person p : srcList){ destList.add(p); } printList(destList); srcList.get(0).setAge(100); printList(destList);
5,Collections的copy(List desc,List src)方法也是浅复制。下边这篇文章的说法是错误的由java中深度复制一伸出Collections.copy的使用
文章称之为深拷贝,说两个list的每个元素所指向的不是同一内存。 代码如下:
List<String> src = new ArrayList<String>(); src.add("111"); src.add("222"); src.add("333"); src.add("444"); List<String> dic = new ArrayList<String>(Arrays.asList(new String[src .size()])); Collections.copy(dic, src);注意:必须用Arrays.asList方法
public static <T> List<T> asList(T... a)返回一个受指定数组支持的固定大小的列表。
如果如下边这样写会抛出数组越界异常
List des1 = new ArrayList( 3 ); Collections.copy(des1,src1);
所以因为des1.size()为0;3表示的是这个List的容纳能力为3,并不是说des1中就有了3个元素。然而进行copy()时候,首先做的是将desc1的size和src1的size大小进行比较,只有当desc1的 size 大于或者等于src1的size时才进行拷贝,否则抛出IndexOutOfBoundsException异常。
实际情形:
仍然是浅复制。误导此文作者的原因是String对象不可改变,如果仿照clone方法举得例子,改成StringBuffer就可以发现实质上还是浅复制了。
二,深复制的方法
序列化
public static <T> List<T> deepCopy(List<T> src) throws IOException, ClassNotFoundException { ByteArrayOutputStream byteOut = new ByteArrayOutputStream(); ObjectOutputStream out = new ObjectOutputStream(byteOut); out.writeObject(src); ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray()); ObjectInputStream in = new ObjectInputStream(byteIn); @SuppressWarnings("unchecked") List<T> dest = (List<T>) in.readObject(); return dest; }
参考文章:一些不靠谱的java.util.List深复制方法
三,浅复制和别名是不同的。
别名是对同一个对象的另一个引用变量。如ArrayList sameList=myList;
sameList和myList是同一个ArrayList对象的引用变量,对myList对象的更改也就是对sameList对象的更改。
上述浅复制方法,如
ArrayList<E> temp2=(ArrayList)temp1.clone();
则是temp2复制了temp1中的元素,这些元素是引用变量,被复制的元素和原本的元素指向同一内存。对temp1中元素引用的对象的修改会影响到temp2中元素引用的对象;若只是将temp1中元素重新引用新的对象,指向新的内存,则temp2中元素仍然引用原本的对象、指向原本的内存。