服务器之家

服务器之家 > 正文

详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)

时间:2021-07-26 11:34     来源/作者:changshuchao

1.序列化实现

?
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
public class CloneUtils {
 
  @SuppressWarnings("unchecked")
  public static <T extends Serializable> T clone(T object){
 
    T cloneObj = null;
    try {
      ByteArrayOutputStream out = new ByteArrayOutputStream();
      ObjectOutputStream obs = new ObjectOutputStream(out);
      obs.writeObject(object);
      obs.close();
 
      ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
      ObjectInputStream ois = new ObjectInputStream(ios);
      cloneObj = (T) ois.readObject();
 
 
 
    }catch (Exception e){
      e.printStackTrace();
    }
    return cloneObj;
 
  }
 
}

2.主代码

?
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
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
public class TestString {
  public static void main(String[] args) {
    TestString test = new TestString();
    System.out.println("-------浅拷贝---------");
    test.qianCopyTest();
 
    System.out.println();
 
    System.out.println("--------使用clone深拷贝--------");
    test.defaultCloneTest();
 
    System.out.println();
 
    System.out.println("--------使用序列化实现对象的拷贝--------");
    test.streamClonrTest();
 
 
    System.out.println("--------耗时对比--------");
    System.out.println("耗时1 : "+ test.qianCopyCost());
    System.out.println("耗时2 : "+ test.CloneCopyCost());
    System.out.println("耗时3 : "+ test.StreamCopyCost());
  }
 
  /*浅拷贝*/
  private void qianCopyTest() {
    String s = "cd";
    change(s);
    System.out.println(s);
    System.out.println("----------------");
    String b = new String("cd");
    change(b);
    System.out.println(b);
    System.out.println("----------------");
    int me = 1;
    change(me);
    System.out.println(me);
    System.out.println("----------------");
    Person person = new Person("我", 13,new Email("我"));
    change(person);
    System.out.println(person.toString());
  }
 
  /*使用默认的clone方法,需要Person实现Cloneable接口*/
  private void defaultCloneTest(){
    Person person = new Person("我", 13,new Email("我"));
    Person person1 = person.clone();
    Person person2 = person.clone();
    System.out.println("person : 【"+person+"】");
    System.out.println("person1 : 【"+person1+"】");
    System.out.println("person2 : 【"+person2+"】");
    //改一个就会触动全部!! 这就是使用默认的clone方法的弊端
    /*该clone()方法是使用Object类的clone()方法,但是该方法存在一个缺陷,它并不会将对象的所有属性全部拷贝过来,而是有选择性的拷贝,基本规则如下:
       1、 基本类型
         如果变量是基本很类型,则拷贝其值,比如int、float等。
       2、 对象
         如果变量是一个实例对象,则拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。
       3、 String字符串
         若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有紫都城对象保持不变。*/
    person.getEmail().setContent("你");
    System.out.println("之后的person : 【"+person+"】");
    System.out.println("之后的person1 : 【"+person1+"】");
    System.out.println("之后的person2 : 【"+person2+"】");
  }
 
  /*使用序列化实现对象的拷贝,需要对象以及对象中的其他对象都要实现Serializable接口*/
  private void streamClonrTest(){
    Person person = new Person("我", 13,new Email("我"));
    Person person1 = CloneUtils.clone(person);
    Person person2 = CloneUtils.clone(person);
    System.out.println("person : 【"+person+"】");
    System.out.println("person1 : 【"+person1+"】");
    System.out.println("person2 : 【"+person2+"】");
    person.getEmail().setContent("你");
    System.out.println("之后的person : 【"+person+"】");
    System.out.println("之后的person1 : 【"+person1+"】");
    System.out.println("之后的person2 : 【"+person2+"】");
  }
 
  private static void change(String x) {
    x = "ab";
  }
 
  private static void change(int x) {
    x = 2;
  }
 
  private static void change(Person x) {
    x = new Person("你", 20, new Email("你"));
  }
 
  private long qianCopyCost(){
    long start = System.currentTimeMillis();
    Person person = new Person("我", 13,new Email("我"));
    List<Person> list = new ArrayList<>();
    for(int i = 0;i<=10000;i++){
      list.add(new Person("你", 20, new Email("你")));
    }
    return System.currentTimeMillis()-start;
  }
 
  private long CloneCopyCost(){
    long start = System.currentTimeMillis();
    Person person = new Person("我", 13,new Email("我"));
    List<Person> list = new ArrayList<>();
    for(int i = 0;i<=10000;i++){
      list.add(person.clone());
    }
    return System.currentTimeMillis()-start;
  }
 
  private long StreamCopyCost(){
    long start = System.currentTimeMillis();
    Person person = new Person("我", 13,new Email("我"));
    List<Person> list = new ArrayList<>();
    for(int i = 0;i<=10000;i++){
      list.add(CloneUtils.clone(person));
    }
    return System.currentTimeMillis()-start;
  }
 
}
 
class Person implements Serializable, Cloneable {
 
  private static final long serialVersionUID = -8584225043397465132L;
  private String name;
  private int age;
 
  public void setEmail(Email email) {
    this.email = email;
  }
 
  private Email email;
 
  public Email getEmail() {
    return email;
  }
 
  public void setName(String name) {
    this.name = name;
  }
 
  public void setAge(int age) {
    this.age = age;
  }
 
  public Person(String name, int age, Email email) {
    this.name = name;
    this.age = age;
    this.email = email;
  }
 
  @Override
  public String toString() {
    return "name : " + name + " | age : " + age +" | content : "+email.getContent();
  }
 
  @Override
  protected Person clone() {
    Person person = null;
    try {
      person = (Person) super.clone();
      /*如果加上下一行 “使用clone深拷贝” 就不会改一处其他都改变了*/
      person.setEmail(new Email(person.getEmail().getContent()));
    } catch (CloneNotSupportedException e) {
      e.printStackTrace();
    }
 
    return person;
  }
}
 
class Email implements Serializable {
 
  private static final long serialVersionUID = 1426052929769365539L;
  private String content;
 
  public void setContent(String content) {
    this.content = content;
  }
 
  public String getContent() {
    return content;
  }
 
  public Email(String content) {
    this.content = content;
  }
}

测试了一下时间:
输出:
-------浅拷贝---------
cd

cd

1

name : 我 | age : 13 | content : 我

--------使用clone深拷贝--------
person : 【name : 我 | age : 13 | content : 我】
person1 : 【name : 我 | age : 13 | content : 我】
person2 : 【name : 我 | age : 13 | content : 我】
之后的person : 【name : 我 | age : 13 | content : 你】
之后的person1 : 【name : 我 | age : 13 | content : 我】
之后的person2 : 【name : 我 | age : 13 | content : 我】

--------使用序列化实现对象的拷贝--------
person : 【name : 我 | age : 13 | content : 我】
person1 : 【name : 我 | age : 13 | content : 我】
person2 : 【name : 我 | age : 13 | content : 我】
之后的person : 【name : 我 | age : 13 | content : 你】
之后的person1 : 【name : 我 | age : 13 | content : 我】
之后的person2 : 【name : 我 | age : 13 | content : 我】
--------耗时对比--------
耗时1 : 2
耗时2 : 1
耗时3 : 338

以上所述是小编给大家介绍的java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)详解整合,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对服务器之家网站的支持!

原文链接:https://blog.csdn.net/changshuchao/article/details/88406171

相关文章

热门资讯

2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全
2020微信伤感网名听哭了 让对方看到心疼的伤感网名大全 2019-12-26
yue是什么意思 网络流行语yue了是什么梗
yue是什么意思 网络流行语yue了是什么梗 2020-10-11
背刺什么意思 网络词语背刺是什么梗
背刺什么意思 网络词语背刺是什么梗 2020-05-22
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总
苹果12mini价格表官网报价 iPhone12mini全版本价格汇总 2020-11-13
2021德云社封箱演出完整版 2021年德云社封箱演出在线看
2021德云社封箱演出完整版 2021年德云社封箱演出在线看 2021-03-15
返回顶部