对象的拷贝又被成为对象的克隆。对象的拷贝分为两种:浅拷贝和深拷贝。
浅拷贝
浅复制(浅克隆)被复制对象的所有变量都含有与原来对象相同的值,而所有的对其他对象的引用仍然只指向原来的对象,换言之,浅复制仅仅复制锁考虑的对象,而不复制它所引用的对象。
对象的浅拷贝是通过调用clone方法来实现的。
浅拷贝需要注意的细节:
1. 如果一个对象需要调用clone的方法克隆,那么该对象所属的类必须要实现Cloneable接口。
2. Cloneable接口只不过是一个标识接口而已,没有任何方法。
3. 对象的浅克隆也不会调用到构造方法的。
代码示例:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 //实体类代码 2 class Address{ 3 4 String city; 5 6 public Address(String city){ 7 this.city = city; 8 } 9 10 } 11 12 public class Person implements Cloneable{ 13 int id; 14 15 String name; 16 17 Address address; 18 19 public Person(int id, String name) { 20 this.id = id; 21 this.name = name; 22 } 23 public Person(int id, String name, Address address) { 24 this.id = id; 25 this.name = name; 26 this.address = address; 27 System.out.println("=======构造方法调用了==="); 28 } 29 @Override 30 public String toString() { 31 return "编号:"+ this.id+" 姓名:"+ this.name+" 地址:"+ address.city; 32 } 33 @Override 34 public Object clone() throws CloneNotSupportedException { 35 return super.clone(); 36 } 37 } 38 //测试类代码 39 public class DemoCopy { 40 public static void main(String[] args) throws CloneNotSupportedException { 41 Person p1 = new Person(110, "Nick",new Address("济南")); 42 Person p2 = (Person)p1.clone(); 43 p2.address.city = "北京"; 44 System.out.println("p1的内容:"+p1); 45 System.out.println("p2的内容:"+p2); 46 } 47 }
深拷贝
深复制(深克隆)被复制对象的所有变量都含有与原来的对象相同的值,除去那些引用其他对象的变量,那些引用其他对象的变量将指向被复制过的新对象,而不再试原有的那些被引用的对象,换言之,深复制把要复制的对象所引用的对象都复制了一遍。
把对象写到流里的过程是串行化(Serilization)过程,但是在Java程序师圈子里又非常形象地称为“冷冻”或者“腌咸菜(picking)”过程;而把对象从流中读出来的并行化(Deserialization)过程则叫做“解冻”或者“回鲜(depicking)”过程。应当指出的是,写在流里的是对象的一个拷贝,而原对象仍然存在于JVM里面,因此“腌成咸菜”的只是对象的一个拷贝,Java咸菜还可以回鲜。
在Java语言里深复制一个对象,常常可以先使对象实现Serializable接口,然后把对象(实际上只是对象的一个拷贝)写到一个流里(腌成咸菜),再从流里读出来(把咸菜回鲜),便可以重建对象。
对象的深拷贝是通过对象输入(ObjectInputStream)输出(ObjectOutputStream)流来实现的。
示例代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 //实体类代码 2 class Address implements Serializable{ 3 4 String city; 5 6 public Address(String city){ 7 this.city = city; 8 } 9 10 } 11 12 public class Person implements Serializable{ 13 int id; 14 15 String name; 16 17 Address address; 18 19 public Person(int id, String name) { 20 this.id = id; 21 this.name = name; 22 } 23 public Person(int id, String name, Address address) { 24 this.id = id; 25 this.name = name; 26 this.address = address; 27 System.out.println("=======构造方法调用了==="); 28 } 29 @Override 30 public String toString() { 31 return "编号:"+ this.id+" 姓名:"+ this.name+" 地址:"+ address.city; 32 } 33 34 } 35 //测试代码 36 public class Demo2 { 37 38 public static void main(String[] args) throws IOException, ClassNotFoundException { 39 Address address = new Address("广州"); 40 Person p1 = new Person(110,"狗娃",address); 41 writeObj(p1); 42 Person p2 =readObj(); 43 44 p2.address.city = "长沙"; 45 System.out.println("p1:"+ p1); 46 System.out.println("p2:"+ p2); 47 48 49 } 50 51 52 //再从文件中读取对象的信息 53 public static Person readObj() throws ClassNotFoundException, IOException{ 54 FileInputStream fileInputStream = new FileInputStream("F:\\obj.txt"); 55 //创建对象的输入流对象 56 ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream); 57 return (Person) objectInputStream.readObject(); 58 } 59 60 61 //先要把对象写到文件上。 62 public static void writeObj(Person p) throws IOException{ 63 //建立一个文件 的输出流对象 64 FileOutputStream fileOutputStream = new FileOutputStream("F:\\obj.txt"); 65 //建立对象的输出流 66 ObjectOutputStream objectOutputStream = new ObjectOutputStream(fileOutputStream); 67 //把对象写出 68 objectOutputStream.writeObject(p); 69 //关闭资源 70 objectOutputStream.close(); 71 72 } 73 }