今天看list和ArrayList的区别,发现了一个问题,
着实让我为我之前的代码出了一把汗,
之前做项目的时候用到了java的克隆,只是实现了Cloneable接口,
然后进行对象克隆并且复制、保存到数据库中,
为什么出汗,因为今天看到ArrayList的clone方法竟然是浅复制,
ArrayList list1 = new ArrayList(); list1.add(new Object()); ArrayList list2 = (ArrayList) list1.clone(); System.out.println(list1.get(0)); System.out.println(list2.get(0));
输出结果:
java.lang.Object@de6ced java.lang.Object@de6ced
我勒个去,这两个list中的对象进入是同一个地址的,也就是说,相当于列表中的元素使用同一个对象:
Object obj = new Object(); ArrayList list1 = new ArrayList(); list1.add(obj); ArrayList list2 = new ArrayList(); list2.add(obj); System.out.println(list1.get(0)); System.out.println(list2.get(0));
这样做有一个很大的问题,就是说如果obj对象不是一个Object对象,而是一个自定义的对象,那么obj的一个属性的修改就会影响到list1 和list2里面的两个值。
因为我之前写的代码就是先创建一个自定义类对象,
然后for循环,对这个对象克隆,然后赋予不同的值,
最后保存到数据库中,
你说你吓人么 。
还好看到了光明:
备注:GenericCollection实现了Cloneable接口
GenericCollection gc = new GenericCollection(); GenericCollection gc2 = (GenericCollection)gc.clone(); System.out.println(gc); System.out.println(gc2);
数据出结果:
com.hung.test.GenericCollection@18dfef8 com.hung.test.GenericCollection@15e83f9
悬着的石头总算落地了,
呵呵 这两个对象的地址不一样,
说明之前写的程序不会有影响。
也说明了一个问题:
深复制:其实实现Cloneable接口的对象,调用clone方法的时候,并不是浅复制,而是创建了新的对象,并把每个属性值都重新赋给新对象的对应属性,
浅复制:其实只是把对象的应用地址给你复制了一分而已。
至此
给大家分享一下
欢迎拍砖
-- 2012-10-25 11:48
添加说明 :
说明1:
其实,在Colneable接口的官方文档说明中,是建议覆盖object对象中的clone方法的,同时也建议调用super.clone()方法
但是我认为这样就多次一举了,如果要覆盖Object的clone方法,为什么还要调用super.clone()方法呢,自己定义就好了,可能是从性能方面考虑的吧,
但是这样也给用户提供了一个很好的机会,可以自定义clone方法,这样的话你就可以完全按照自己的意思来定制,
可以仅仅创建一个新对象返回,也可以创建对象之后给对象特定的字段赋值,这样就能打到定制化的效果。
非常好。
说明2:
完全可以只实现结构,而不覆盖Object中的clone方法,我亲自使过,可以的,因为Cloneable结构中没有定义任何方法。