1.浅复制与深复制概念java
⑴浅复制(浅克隆) 工具
被复制对象的全部变量都含有与原来的对象相同的值,而全部的对其余对象的引用仍然指向原来的对象。换言之,浅复制仅仅复制所考虑的对象,而不复制它所引用的对象。 举例说明:设计
常见的List的克隆方式有不少,下面咱们来列举几种常见的List浅复制的方式:code
public static void main(String []args){对象
List<Map<String,String>> list1 = new ArrayList<Map<String, String>>();接口
Map<String,String> map = new HashMap<String, String>();内存
map.put("name", "xiaoming");get
map.put("age", "28");it
list1.add(map);io
//克隆方法1:利用原list1做为参数直接构造方法生成。
List<Map<String,String>> list2 = new ArrayList<Map<String, String>>(list1);
//克隆方法2:手动遍历将原list1中的元素所有添加到复制表中。
for(int i = 0, l = list1.size(); i < l; i++)
list2.add(list1.get(i)); //克隆方法3:调用Collections的静态工具方法 Collections.copy
//克隆方法4:使用System.arraycopy方法进行复制
}
List自身是一个对象,他在存储类类型的时候,只负责存储地址。而存储基本类型的时候,存储的就是实实在在的值。纵然你有千千万万个List,元素仍是那么几个。不管是从新构造,Collections的复制方法,System的复制方法,仍是手动去遍历,结果都同样,这些方法都只改变了ArrayList对象的自己,简单的添加了几个指向老元素的地址。而没作深层次的复制。(及压根没有没有 new新对象 的操做出现。)
有的时候咱们确实须要将这些元素也都复制下来而不是只是用原来内存中的元素。List层实现这个问题。java语言设计之初就考虑进去了,避免操做这些埋在堆内存中的数据,全部操做都去针对能找到他们的地址。地址没了自身还会被GC干掉。因此只好一点点的去遍历,new建立新的对象并赋予原来的值。听说可能以为上述的作法略微调整,因此巧用序列化对象让这些数据在IO流中跑了一圈,能够实现复制。其实把对象序列化到流中,java语言实在是妥协了,毕竟你不能再把地址扔进去吧?再说了io流是要和别的系统交互的,你发给别人一个地址让别人去哪一个堆里找?因此不用多提确定要新开辟堆内存的。
⑵深复制(深克隆)之序列化
被复制对象的全部变量都含有与原来的对象相同的值,除去那些引用其余对象的变量。那些引用其余对象的变量将指向被复制过的新对象,而再也不是原有的那些被引用的对象。换言之,深复制把要复制的对象所引用的对象都复制了一遍。
Java中利用串行化来作深复制(深克隆)(避免重写比较复杂对象的深复制的clone()方法,也能够程序实现断点续传等等功能)
把对象写到流里的过程是串行化(Serilization)过程,可是在Java里又很是形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫作 “解冻”或者“回鲜(depicking)”过程。 应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,所以“腌成咸菜”的只是对象的一个拷贝,Java咸菜还能够回鲜。 在Java语言里深复制一个对象,经常能够先使对象实现Serializable接口,而后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),即可以重建对象。 以下为深复制源代码。
public List<Map<String,String>> deClone(Object obj) throws IOException,OptionalDataException,ClassNotFoundException{
//将对象写到流里
ByteArrayOutoutStream bo=new ByteArrayOutputStream();
ObjectOutputStream oo=new ObjectOutputStream(bo);
oo.writeObject(obj);//从流里读出来
ByteArrayInputStream bi=new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi=new ObjectInputStream(bi);
return(oi.readObject());
}
这样作的前提是对象以及对象内部全部引用到的对象都是可串行化的,不然,就须要仔细考察那些不可串行化的对象或属性能否设成transient,从而将之排除在复制过程以外。