浅复制:在对对象进行复制时,如果对象的字段是值类型,则对该字段进行逐位复制;如果字段是引用类型,则复制引用但是不复制引用的对象。也就是说,对于引用来说,复制后的对象和复制之前的对象都是指向同一块内存。
深复制:在复制的时候,会把引用所指向的对象复制过来,重新开辟一块新的内存。
Java的clone()方法:clone之后的对象是一个新的对象,不等同于之前的对象,但是类型是一样的(getClass()一致)。
Object类有一个clone方法,java中要想复制,必须实现Cloneable接口,并且重写clone()方法,在clone方法里面调用super.clone()。
注意:需要在派生类中将clone方法声明为public,默认是protected。
Clone实现的是浅复制,如何实现深复制呢?只需要在引用的对象中也实现Cloneable接口,并在上一层调用的对象中把克隆对象获取到即可。
public class Resume implements Cloneable{
private String name;
private WorkExperience workexperience;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public WorkExperience getWorkexperience() {
return workexperience;
}
public void setWorkexperience(WorkExperience workexperience) {
this.workexperience = workexperience;
}
@Override
public Resume clone() throws CloneNotSupportedException {
Resume resume= (Resume) super.clone();
//这里进行克隆
resume.workexperience = workexperience.clone();
return resume;
}
public static void main(String[] args ) throws CloneNotSupportedException {
WorkExperience we = new WorkExperience();
we.setCompany("第一家公司");
Resume r = new Resume();
r.setName("第一人");
r.setWorkexperience(we);
Resume r1 = r.clone();
r1.setName("第二人");
r1.getWorkexperience().setCompany("第二家公司");
System.out.println(r.getName()+r.getWorkexperience().getCompany());
System.out.println(r1.getName()+r1.getWorkexperience().getCompany());
}
}
class WorkExperience implements Cloneable{
private String company;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
@Override
public WorkExperience clone() throws CloneNotSupportedException {
return (WorkExperience) super.clone();
}
}
除了使用上述的方法实现深复制,还可以通过序列化实现深复制。
序列化,也就是把对象转换成字节流,然后利用这些字节流可以生成相同状态的对象。
public class Resume2 implements Serializable{
private static final long serialVersionUID = 1L;
private String name;
private WorkExperience2 workexperience;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public WorkExperience2 getWorkexperience() {
return workexperience;
}
public void setWorkexperience(WorkExperience2 workexperience) {
this.workexperience = workexperience;
}
public Object deepClone() throws IOException, ClassNotFoundException {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(this);
ByteArrayInputStream bai = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bai);
return (ois.readObject());
}
public static void main(String[] args ) throws CloneNotSupportedException, ClassNotFoundException, IOException {
WorkExperience2 we = new WorkExperience2();
we.setCompany("第一家公司");
Resume2 r = new Resume2();
r.setName("第一人");
r.setWorkexperience(we);
Resume2 r1 = (Resume2) r.deepClone();
r1.setName("第二人");
r1.getWorkexperience().setCompany("第二家公司");
System.out.println(r.getName()+r.getWorkexperience().getCompany());
System.out.println(r1.getName()+r1.getWorkexperience().getCompany());
}
}
class WorkExperience2 implements Serializable {
private static final long serialVersionUID = 1L;
private String company;
public String getCompany() {
return company;
}
public void setCompany(String company) {
this.company = company;
}
}
ObjectOutputStream 将 Java 对象的基本数据类型和图形写入 OutputStream。可以使用 ObjectInputStream 读取(重构)对象。