Java对象克隆-浅拷贝与深拷贝

目录

1、对象的克隆

1.1 对象的浅拷贝

1.2 对象深拷贝


1、对象的克隆

1.1 对象的浅拷贝

在实际编程过程中,我们常常要遇到这种情况:有一个对象A,在某一时刻A中已经包含了一些有效值,此时可能会需要一个和A完全相同新对象B,并且此后对B任何改动都不会影响到A中的值,也就是说,A与B是两个独立的对象,但B的初始值是由A对象确定的。

要满足这种需求虽然有很多途径,但实现clone()方法是其中最简单,也是最高效的手段。

public class Person implements Cloneable {

   private String name;

   private int age;

   public Person() {

   }

   public Person(String name, int age) {

      this.name = name;

      this.age = age;

   }

   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;

   }

   protected Object clone() {

      Object obj = null;

      try {

         obj = super.clone();

      } catch (CloneNotSupportedException e) {

         e.printStackTrace();

      }

      return obj;

   }

   public String toString() {

      return "Person [name=" + name + ", age=" + age + "]";

   }

}

注意: 该Person 类实现了Cloneable 重写了clone() 方法.

public static void main(String[] args) {

      Person p1 = new Person("jack", 28);

      System.out.println(p1);

      Person p2 = (Person) p1.clone();

      System.out.println(p2);

      // 不是同一个Person 对象.

      System.out.println(p1 == p2);

      // 修改p1 对象属性值,不影响 p2 对象的属性值.

      p1.setAge(30);

      System.out.println(p1);

      System.out.println(p2);

   }

Java的所有类都默认继承java.lang.Object类,在java.lang.Object类中有一个方法clone()。JDK API的说明文档解释这个方法将返回Object对象的一个拷贝。要说明的有两点:一是拷贝对象返回的是一个新对象,而不是一个引用。二是拷贝对象与用new操作符返回的新对象的区别就是这个拷贝已经包含了一些原来对象的信息,而不是对象的初始信息。

1.2 对象深拷贝

注意问题:

请看代码:

package cn.test.gz.myclone;

public class Person implements Cloneable {

   private String name;

   private int age;

   private Address add;

   public Person() {

   }

   public Person(String name, int age, Address add) {

      this.name = name;

      this.age = age;

      this.add = add;

   }

   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 Address getAdd() {

      return add;

   }

   public void setAdd(Address add) {

      this.add = add;

   }

   protected Object clone() {

      Object obj = null;

      try {

         obj = super.clone();

      } catch (CloneNotSupportedException e) {

         e.printStackTrace();

      }

      return obj;

   }

   @Override

   public String toString() {

      return "Person [name=" + name + ", age=" + age + ", add:" + add + "]";

   }

}

package cn.test.gz.myclone;

public class Address {

   private String country;

   private String city;

   public Address() {

   }

   public Address(String country, String city) {

      this.country = country;

      this.city = city;

   }

   public String getCountry() {

      return country;

   }

   public void setCountry(String country) {

      this.country = country;

   }

   public String getCity() {

      return city;

   }

   public void setCity(String city) {

      this.city = city;

   }

   public String toString() {

      return "country=" + country + ", city=" + city;

   }

}

注意:

Address add = new Address("中国", "广州");

      Person p1 = new Person("jack", 28, add);

      add.setCountry("美国");

      System.out.println(p1);

      Person p2 = (Person) p1.clone();

      System.out.println(p2);

      // 克隆的是两个不同的对象

      System.out.println(p1 == p2);

      // 但是对象内部的成员是同一个对象.

      System.out.println(p1.getAdd() == p2.getAdd());

解决办法:

package cn.test.gz.myclone;

public class Address implements Cloneable {

   private String country;

   private String city;

   public Address() {

   }

   public Address(String country, String city) {

      this.country = country;

      this.city = city;

   }

   public String getCountry() {

      return country;

   }

   public void setCountry(String country) {

      this.country = country;

   }

   public String getCity() {

      return city;

   }

   public void setCity(String city) {

      this.city = city;

   }

   public String toString() {

      return "country=" + country + ", city=" + city;

   }

   @Override

   public Object clone() {

      Object obj = null;

      try {

         obj = super.clone();

      } catch (CloneNotSupportedException e) {

         // TODO Auto-generated catch block

         e.printStackTrace();

      }

      return obj;

   }

}

Person 类

protected Object clone() {

      Person p = null;

      try {

         p = (Person) super.clone();

      } catch (CloneNotSupportedException e) {

         e.printStackTrace();

      }

      p.add = (Address) add.clone();

      return p;

   }

当然也可以通过序列化机制来实现对象的克隆.

public static void main(String[] args) throws IOException, ClassNotFoundException {

      Address add = new Address("中国", "广州");

      Person p1 = new Person("jack", 28, add);

      ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream(

            "c:\\person.txt"));

      oos.writeObject(p1);

      ObjectInputStream ois = new ObjectInputStream(new FileInputStream("c:\\person.txt"));

      Person p2=(Person)ois.readObject();

      System.out.println(p1==p2);

      System.out.println(p1.getAdd()==p2.getAdd());

   }

  • 23
    点赞
  • 29
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
Java中,浅拷贝深拷贝都是用于复制对象的概念。 浅拷贝是指创建一个新对象,然后将原始对象的非静态字段复制到新对象中。如果字段是基本类型,则对该字段执行逐位复制;如果字段是引用类型,则复制引用而不是引用的对象深拷贝是指创建一个新对象,然后递归地复制原始对象及其所有引用的对象。这意味着在深拷贝中,即使字段是引用类型,也会创建一个新的对象并复制其内容。 要实现浅拷贝,可以使用`clone()`方法。该方法在`Object`类中定义,并且可以由任何类继承和覆盖。要使一个类支持克隆,需要实现`Cloneable`接口,并且覆盖`clone()`方法。 示例代码如下: ```java class MyClass implements Cloneable { private int value; private MyObject obj; public MyClass(int value, MyObject obj) { this.value = value; this.obj = obj; } public int getValue() { return value; } public MyObject getObj() { return obj; } @Override public Object clone() throws CloneNotSupportedException { return super.clone(); } } class MyObject { private String name; public MyObject(String name) { this.name = name; } public String getName() { return name; } } public class Main { public static void main(String[] args) throws CloneNotSupportedException { MyObject obj = new MyObject("Object 1"); MyClass obj1 = new MyClass(10, obj); MyClass obj2 = (MyClass) obj1.clone(); System.out.println(obj1.getObj().getName()); // Output: Object 1 System.out.println(obj2.getObj().getName()); // Output: Object 1 obj.setName("Object 2"); System.out.println(obj1.getObj().getName()); // Output: Object 2 (原始对象浅拷贝对象引用同一个对象) System.out.println(obj2.getObj().getName()); // Output: Object 2 } } ``` 需要注意的是,浅拷贝只复制了对象的引用,而不是对象本身。因此,如果修改了原始对象中的引用对象,那么浅拷贝对象也会受到影响。 要实现深拷贝,可以使用序列化和反序列化。通过将对象写入字节流,然后从字节流读取对象,可以创建一个全新的对象。这种方法需要确保所有相关的类都实现了`Serializable`接口。 示例代码如下: ```java import java.io.*; class MyClass implements Serializable { private int value; private MyObject obj; public MyClass(int value, MyObject obj) { this.value = value; this.obj = obj; } public int getValue() { return value; } public MyObject getObj() { return obj; } } class MyObject implements Serializable { private String name; public MyObject(String name) { this.name = name; } public String getName() { return name; } } public class Main { public static <T> T deepCopy(T object) throws IOException, ClassNotFoundException { ByteArrayOutputStream baos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(baos); oos.writeObject(object); ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bais); return (T) ois.readObject(); } public static void main(String[] args) throws IOException, ClassNotFoundException { MyObject obj = new MyObject("Object 1"); MyClass obj1 = new MyClass(10, obj); MyClass obj2 = deepCopy(obj1); System.out.println(obj1.getObj().getName()); // Output: Object 1 System.out.println(obj2.getObj().getName()); // Output: Object 1 obj.setName("Object 2"); System.out.println(obj1.getObj().getName()); // Output: Object 1 (原始对象深拷贝对象引用不同的对象) System.out.println(obj2.getObj().getName()); // Output: Object 1 } } ``` 通过序列化和反序列化可以实现深拷贝,因为它会创建一个全新的对象,而不是引用原始对象对象。这样,即使修改了原始对象中的引用对象深拷贝对象也不会受到影响。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

棉花糖老丫

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值