问题一:为什么要使用克隆?
在对一个对象进行处理,又想要保留原有的数据进行接下来的操作。
克隆针对的是类的实例。
问题二:如何实现对象克隆?
- 实现Cloneable接口,重写clone()方法;
clone方法是浅拷贝,即如果类中属性有自定义的引用类型,只拷贝引用,不拷贝引用指向的对象。
public class CloneTest {
public static void main(String[] args) throws Exception {
Person p1 = new Person("aa", 20,new Car("报名", 110));
Person p2 = (Person)p1.clone();
System.out.println(p2);
p2.getCar().setCname("劳斯莱斯");;
System.out.println(p1);
System.out.println(p2);
}
}
public class Person implements Cloneable{
private String name;
private int age;
private Car car;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Person(String name, int age, Car car) {
super();
this.name = name;
this.age = age;
this.car = car;
}
@Override
protected Object clone() throws CloneNotSupportedException {
// TODO Auto-generated method stub
return super.clone();
}
}
package com.zzz.test;
import java.io.Serializable;
public class Car implements Serializable{
private static final long serialVersionUID = -8567991418055419505L;
private String cname;
private int speed;
@Override
public String toString() {
return "Car [cname=" + cname + ", speed=" + speed + "]";
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Car(String cname, int speed) {
super();
this.cname = cname;
this.speed = speed;
}
}
结果
Person [name=aa, age=20, car=Car [cname=报名, speed=110]]
Person [name=aa, age=20, car=Car [cname=劳斯莱斯, speed=110]]
Person [name=aa, age=20, car=Car [cname=劳斯莱斯, speed=110]]
可以看出引用被克隆的对象引用变量跟着改变。不是引用变量不会改变
2.实现Serializable接口,完成深拷贝;
基于序列化实现的克隆不仅仅是深度克隆,更重要是通过泛型限定,可以检测出要克隆的对象是否支持序列化,这项检查是编译器完成的。
克隆工具类
public class MyUtil {
private MyUtil() {
throw new AssertionError();
}
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj) throws Exception {
ByteArrayOutputStream bout = new ByteArrayOutputStream();
System.out.println(bout.toString()+"*");
ObjectOutputStream oos = new ObjectOutputStream(bout);
System.out.println(oos.toString()+"**");
oos.writeObject(obj);
ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bin);
System.out.println(ois.toString()+"***");
Object object = ois.readObject();
return (T)object;
}
}
对象
public class Person implements Serializable{
private static final long serialVersionUID = 1558994087258136676L;
private String name;
private int age;
private Car car;
@Override
public String toString() {
return "Person [name=" + name + ", age=" + age + ", car=" + car + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public Person(String name, int age, Car car) {
super();
this.name = name;
this.age = age;
this.car = car;
}
}
public class Car implements Serializable{
private static final long serialVersionUID = -8567991418055419505L;
private String cname;
private int speed;
@Override
public String toString() {
return "Car [cname=" + cname + ", speed=" + speed + "]";
}
public String getCname() {
return cname;
}
public void setCname(String cname) {
this.cname = cname;
}
public int getSpeed() {
return speed;
}
public void setSpeed(int speed) {
this.speed = speed;
}
public Car(String cname, int speed) {
super();
this.cname = cname;
this.speed = speed;
}
}
测试类
public class CloneTest {
public static void main(String[] args) {
try {
Person p1 = new Person("在这种", 20, new Car("宝马", 180));
Person p2 = MyUtil.clone(p1);
p2.getCar().setCname("劳斯莱斯");
System.out.println(p1);
System.out.println(p2);
} catch (Exception e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
}
}
结果
*
java.io.ObjectOutputStream@6d06d69c**
java.io.ObjectInputStream@448139f0***
Person [name=在这种, age=20, car=Car [cname=宝马, speed=180]]
Person [name=在这种, age=20, car=Car [cname=劳斯莱斯, speed=180]]
问题三:深拷贝浅拷贝的区别是什么?
- 浅拷贝只是复制了对象的引用地址,拷贝对象和被拷贝对象指向同一个内存地址,所以修改其中一个,任意一个都会变化。而对于基本类型对象改变一个并不会影响另一个。
- 深拷贝是将对象及值复制,两个对象改变其中一个另一个不会改变