浅复制:在对对象进行复制时,如果对象的字段是值类型,则对该字段进行逐位复制;如果字段是引用类型,则复制引用但是不复制引用的对象。也就是说,对于引用来说,复制后的对象和复制之前的对象都是指向同一块内存。
深复制:在复制的时候,会把引用所指向的对象复制过来,重新开辟一块新的内存。
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 读取(重构)对象。