1.什么是"克隆"?
由一个现有对象A,复制生成一个新的对象B的过程(B的初始值是由A对象确定的)。
- 拷贝对象返回的是一个新对象,而不是一个引用。
- 拷贝对象与用 new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。
2.浅克隆与深克隆
- 浅拷贝的效果就是拷贝对象时仅仅拷贝对象本身(包括对象中的基本变量和不可变引用变量(比如String类型属性))
- 深拷贝不仅拷贝对象本身,而且拷贝对象包含的引用指向的所有对象。
3.实现克隆的方法
- 实现Cloneable
- 在要实现克隆的对象类中实现Cloneable接口
Cloneable接口为标记接口(标记接口为用户标记实现该接口的类具有该接口标记的功能,常见的标记接口有Serializable、Cloneable、RandomAccess),如果没有实现该接口,在调用clone方法时就会抛出CloneNotSupportException异常。
- 在类中重写Object的clone方法。
1.重写是为了扩大访问权限【Object类的clone方法使用protected【只有Object的同包和直接子类才可以访问】修饰】
2.为了实现深拷贝【Object的clone表现出来的是浅拷贝。对于可变的引用属性也使用clone方法,即递归调用clone即可实现深克隆】
- 对象序列化
对象序列化也可以实现对象克隆,并且是深克隆,但是(序列化)串行化却很耗。
- 代码示例
//Teacher类
public class Teacher implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
Teacher (String name, int age) {
this.name = name;
this.age = age;
}
//学生类
public class Student implements Serializable {
private static final long serialVersionUID = 1L;
String name;
int age;
Teacher t;
Student (String name, int age, Teacher t) {
this.name = name;
this.age = age;
this.t = t;
}
public Object deepClone() throws IOException, OptionalDataException,
ClassNotFoundException {
// 将对象写到流里(序列化)
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream oo = new ObjectOutputStream(bo);
oo.writeObject(this);
// 从流里读出来(反序列化)
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
}
}
//测试类
public class TestDemo {
/**
* @param args
*/
public static void main(String[] args) throws OptionalDataException,
IOException, ClassNotFoundException {
long t1 = System.currentTimeMillis();
Teacher t = new Teacher("wangwu", 50);
Student s1 = new Student("zhangsan", 18, t);
Student s2 = (Student) s1.deepClone();
s2.t.name = "lisi";
s2.t.age = 30;
System.out.println("name=" + s1.t.name + "," + "age=" + s1.t.age); // 学生1的教师不改变。
long t2 = System.currentTimeMillis();
System.out.println(t2-t1);
}
}
- BeanUtils.copyProperties
- spring的BeanUtils.copyProperties实现的浅克隆
- 如果要实现深克隆,需要对于引用属性也调用BeanUtils.copyProperties,即循环copy
- 第三方框架
对象复制工具类,实现方法如下:
- 复制对象(深度拷贝)
- 复制集合(深度拷贝)
- 复制对象到指定类(深度拷贝)
- 复制集合到指定类(深度拷贝)
- 引入maven依赖
<!-- 对象拷贝 -->
<dependency>
<groupId>uk.com.robust-it</groupId>
<artifactId>cloning</artifactId>
<version>1.9.12</version>
</dependency>
<dependency>
<groupId>com.alibaba</groupId>
<artifactId>fastjson</artifactId>
<version>1.2.47</version>
</dependency>
- 工具类
import com.alibaba.fastjson.JSON;
import com.rits.cloning.Cloner;
import java.util.ArrayList;
import java.util.List;
/**
* Bean工具类
*
*/
public class BeanUtils {
private static final Cloner cloner = new Cloner();
/**
* 复制对象(深度拷贝)
* @param object
* @param <T>
* @return
*/
public static <T> T clone(final T object){
if (object == null) {
return null;
}
return cloner.deepClone(object);
}
/**
* 复制集合(深度拷贝)
* @param object
* @param <T>
* @return
*/
public static <T> List<T> cloneList(final List<T> object){
if (object == null) {
return null;
}
return cloner.deepClone(object);
}
/**
* 复制对象到指定类(深度拷贝)
* @param object
* @param destclas 指定类
* @param <T>
* @return
*/
public static <T> T clone(final Object object, Class<T> destclas){
if (object == null) {
return null;
}
String json = JSON.toJSONString(object);
return JSON.parseObject(json, destclas);
}
/**
* 复制集合到指定类(深度拷贝)
* @param object
* @param destclas 指定类
* @param <T>
* @return
*/
public static <T> List<T> cloneList(List<?> object, Class<T> destclas) {
if (object == null) {
return new ArrayList<T>();
}
String json = JSON.toJSONString(object);
return JSON.parseArray(json, destclas);
}
}