Java对象深复制与浅复制实例详解

时间:2021-07-09 06:52:44

 Java对象深复制浅复制实例详解

我们在遇到一些业务场景的时候经常需要对对象进行复制,对于对象的复制一般有两种方式,深复制和浅复制

浅复制:对象的复制仅是对象本身,对象引用的其它对方并不会复制。

深复制:对象的复制包含对象引用的对象。

Java所有对象的基类提供了clone方法,但是这个方法是protected native修饰,因此只暴露给之类去重写,外部是无法直接调用的。

我们现在来测试两种复制,首选是浅复制,浅复制要实现Cloneable接口。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
// 课程对象
class Class {
  private String name;
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
}
// 学生对象
class User implements Cloneable {
  private String name;
  private Long id;
  // 课程引用
  private Class c;
 
  public Class getC() {
    return c;
  }
 
  public void setC(Class c) {
    this.c = c;
  }
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public Long getId() {
    return id;
  }
 
  public void setId(Long id) {
    this.id = id;
  }
 
  @Override
  protected Object clone() throws CloneNotSupportedException {
    return super.clone();
  }
 
  @Override
  public int hashCode() {
    return super.hashCode();
  }
 
  @Override
  public boolean equals(Object obj) {
 
    if (obj instanceof User) {
      User user = (User) obj;
      if (this.id == user.getId() && this.getName() == user.getName()) {
        return true;
      }
      if (user.getId().equals(this.id)
          && user.getName().equals(this.name)) {
        return true;
      }
      return false;
    } else
      return false;
  }
 
}

我们来测试:

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
User user1 = new User();
   User user2 = user1;
 
   User user3 = (User) user1.clone();
 
   System.out.println(user1 == user2);
   System.out.println(user3 == user1);
   System.out.println(user3.equals(user1));
   System.out.println(user3.getName() == user3.getName());// true,浅复制
 
   Class c = new Class();
   c.setName("语文");
   user1.setC(c);
   // 测试复制深度
   User user4 = (User) user1.clone();
   System.out.println(user4.getC() == user1.getC()); // true,说明引用的对象依然是同一个对象

对象的复制并没复制引用所指向的对象class,复制出来的引用指向的同一个地址。

深复制采用序列化与反序列的方式去获取,也有种说法类似于腌菜,用流的方式腌制进去又取出来,实现深度复制。

?
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
class Car implements Serializable {
  /**
   *
   */
  private static final long serialVersionUID = 42342L;
  private String name;
 
  public String getName() {
    return name;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
}
 
// 深复制
class People implements Serializable{
  /**
   *
   */
  private static final long serialVersionUID = 543535212412L;
  private Car car;
 
  public Car getCar() {
    return car;
  }
 
  public void setCar(Car car) {
    this.car = car;
  }
 
  public People deepClone() throws IOException, ClassNotFoundException {
    // 腌制
    ByteArrayOutputStream out = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(out);
    oos.writeObject(this);
    // 取出
    ByteArrayInputStream input = new ByteArrayInputStream(out.toByteArray());
    ObjectInputStream ois = new ObjectInputStream(input);
    return (People) ois.readObject();
  }
 
}

测试深复制:

?
1
2
3
4
5
6
7
8
9
10
11
12
// 深复制
    Car car = new Car();
    car.setName("benz");
    People p = new People();
    p.setCar(car);
 
    try {
      People p2 = p.deepClone();
      System.out.println(p2.getCar() == p.getCar()); // false,说明引用的对象也进行了复制
    } catch (ClassNotFoundException | IOException e) {
      e.printStackTrace();
    }

例外提及一下生成对象的五种办法:

1.new
2.Class类的newInstance
3.Constructor类newInstance
4.Clone方式
5.反序列化的方式

其中2与3即是反射的方式。

感谢阅读,希望能帮助到大家,谢谢大家对本站的支持!

原文链接:http://blog.csdn.net/micro_hz/article/details/54576281