好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

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

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

查看更多关于详解java中的深拷贝和浅拷贝(clone()方法的重写、使用序列化实现真正的深拷贝)的详细内容...

  阅读:17次