JAVA 對象拷貝
為什么需要有對象拷貝?
對象拷貝相對的自然是引用拷貝。java初學者經常會問,我這個方法要改變一個對象的屬性,可以把參數傳進去了,為什么沒有改變了?
——基本數據類型傳值,而對象傳引用或引用的拷貝。
而有時候我們要獲取到一個當前狀態的對象復制品,他們是兩個獨立對象。不再是引用或者引用拷貝(實質都是指向對象本身)。就是說a是b的拷貝,b發生變化的時候,不要影響a。
對象拷貝有淺拷貝和深度拷貝兩種。
1)淺拷貝
淺拷貝是指對象中基本數據類型得到拷貝,而引用數據類型并未拷貝。
提到拷貝自然和clone聯系起來了,所有具有clone功能的類都有一個特性,那就是它直接或間接地實現了Cloneable接口。
否則,我們在嘗試調用clone()方法時,將會觸發CloneNotSupportedException異常。
eg:
?1
public
?
class
?DOG?
implements
?Cloneable
?2
{
?3
????
public
?DOG(String?name,?
int
?age)
?4
????
{
?5
????????
this
.name?
=
?name;
?6
????????
this
.age?
=
?age;
?7
????}
?8
?9
????
public
?String?getName()
10
????
{
11
????????
return
?
this
.name;
12
????}
13
14
????
public
?
int
?getAge()
15
????
{
16
????????
return
?
this
.age;
17
????}
18
19
????
public
?Object?clone()
20
????
{
21
????????
try
22
????????
{
23
????????????
return
?
super
.clone();
24
25
????????}
?
catch
?(CloneNotSupportedException?e)
26
????????
{
27
????????????
return
?
null
;
28
????????}
29
????}
30
31
????
public
?String?name;
32
33
????
private
?
int
?age;
34
35
????
//
test
36
????
public
?
static
?
void
?main(String[]?args)
37
????
{
38
????????DOG?dog1?
=
?
new
?DOG(
"
xiaogou
"
,?
2
);
39
????????DOG?dog2?
=
?(DOG)?dog1.clone();
40
????????dog1.name?
=
?
"
dagou
"
;
41
????????System.out.println(dog2.getName());
42
????????System.out.println(dog2.getAge());
43
????????System.out.println(dog1.getName());
44
????????System.out.println(dog1.getAge());
45
46
????}
47
48
}
49
運行結果:
xiaogou
2
dagou
2
2)深度拷貝
相對淺拷貝。實現對象中基本數據類型和引用數據類型的拷貝。
請先看下面代碼:
?
?1
class
?AAA
?2
{
?3
????
public
?AAA(String?name)
?4
????
{
?5
????????
this
.name?
=
?name;
?6
????}
?7
?8
????
public
?String?name;
?9
}
10
11
class
?DOG?
implements
?Cloneable
12
{
13
????
public
?DOG(String?name,?
int
?age,?AAA?birthday)
14
????
{
15
????????
this
.name?
=
?name;
16
????????
this
.age?
=
?age;
17
????????
this
.birthday?
=
?birthday;
18
????}
19
20
????
public
?String?getName()
21
????
{
22
????????
return
?name;
23
????}
24
25
????
public
?
int
?getAge()
26
????
{
27
????????
return
?age;
28
????}
29
30
????
public
?AAA?getBirthday()
31
????
{
32
????????
return
?birthday;
33
????}
34
35
????
public
?String?getBirth(AAA?a)
36
????
{
37
????????
return
?a.name;
38
????}
39
40
????
public
?String?name;
41
42
????
private
?
int
?age;
43
44
????
public
?AAA?birthday;
45
46
????
public
?Object?clone()
47
????
{
48
????????
try
49
????????
{
50
????????????
super
.clone();
51
????????????
return
?
super
.clone();
52
????????}
?
catch
?(Exception?e)
53
????????
{
54
????????????
return
?
null
;
55
????????}
56
????}
57
}
58
59
public
?
class
?TestClone
60
{
61
????
public
?
static
?
void
?main(String[]?args)
62
????
{
63
????????AAA?Day?
=
?
new
?AAA(
"
test
"
);
64
????????DOG?dog1?
=
?
new
?DOG(
"
xiaogou
"
,?
2
,?Day);
65
????????DOG?dog2?
=
?(DOG)?dog1.clone();
66
????????
//
??dog2.birthday?=?(AAA)?dog1.birthday.clone();?
67
????????dog1.birthday.name?
=
?
"
333
"
;
68
????????System.out.println(dog1.getBirth(dog1.birthday));
69
????????System.out.println(dog2.getBirth(dog2.birthday));
70
????}
71
}
72
運行結果是:
333
333
而真正要實現拷貝還的加點代碼,如下請對比上面和下面代碼的異同之處:
?1
class
?AAA?
implements
?Cloneable
?2
{
?3
????
public
?AAA(String?name)
?4
????
{
?5
????????
this
.name?
=
?name;
?6
????}
?7
?8
????
public
?Object?clone()
?9
????
{
10
????????
try
11
????????
{
12
????????????
super
.clone();
13
????????????
return
?
super
.clone();
14
????????}
?
catch
?(Exception?e)
15
????????
{
16
????????????
return
?
null
;
17
????????}
18
????}
19
20
????
public
?String?name;
21
}
22
23
class
?DOG?
implements
?Cloneable
24
{
25
????
public
?DOG(String?name,?
int
?age,?AAA?birthday)
26
????
{
27
????????
this
.name?
=
?name;
28
????????
this
.age?
=
?age;
29
????????
this
.birthday?
=
?birthday;
30
????}
31
32
????
public
?String?getName()
33
????
{
34
????????
return
?name;
35
????}
36
37
????
public
?
int
?getAge()
38
????
{
39
????????
return
?age;
40
????}
41
42
????
public
?AAA?getBirthday()
43
????
{
44
????????
return
?birthday;
45
????}
46
47
????
public
?String?getBirth(AAA?a)
48
????
{
49
????????
return
?a.name;
50
????}
51
52
????
public
?String?name;
53
54
????
private
?
int
?age;
55
56
????
public
?AAA?birthday;
57
58
????
public
?Object?clone()
59
????
{
60
????????
try
61
????????
{
62
????????????
super
.clone();
63
????????????
return
?
super
.clone();
64
????????}
?
catch
?(Exception?e)
65
????????
{
66
????????????
return
?
null
;
67
????????}
68
????}
69
}
70
71
public
?
class
?TestClone
72
{
73
????
public
?
static
?
void
?main(String[]?args)
74
????
{
75
????????AAA?Day?
=
?
new
?AAA(
"
test
"
);
76
????????DOG?dog1?
=
?
new
?DOG(
"
xiaogou
"
,?
2
,?Day);
77
????????DOG?dog2?
=
?(DOG)?dog1.clone();
78
????????dog2.birthday?
=
?(AAA)?dog1.birthday.clone();
//
特別注意這里
79
????????dog1.birthday.name?
=
?
"
333
"
;
80
????????System.out.println(dog1.getBirth(dog1.birthday));
81
????????System.out.println(dog2.getBirth(dog2.birthday));
82
????}
83
}
84
運行結果:
333
test
這樣基本就達到了我們當初的母的。
但是明顯的這種方法還是有許多不足,人們總是希望一個clone就是對象直接克隆。而上面還要對對象中的對象遞歸使用clone。下面提供一種更高級點的做法:
?
?1
import
?java.io.
*
;
?2
?3
class
?AAA?
implements
?Serializable
?4
{
?5
????
public
?AAA(String?name)
?6
????
{
?7
????????
this
.name?
=
?name;
?8
????}
?9
10
????
public
?String?name;
11
}
12
13
class
?DOG?
extends
?SerialCloneable
14
{
15
????
public
?DOG(String?name,?
int
?age,?AAA?birthday)
16
????
{
17
????????
this
.name?
=
?name;
18
????????
this
.age?
=
?age;
19
????????
this
.birthday?
=
?birthday;
20
????}
21
22
????
public
?String?getName()
23
????
{
24
????????
return
?name;
25
????}
26
27
????
public
?
int
?getAge()
28
????
{
29
????????
return
?age;
30
????}
31
32
????
public
?AAA?getBirthday()
33
????
{
34
????????
return
?birthday;
35
????}
36
37
????
public
?String?getBirth(AAA?a)
38
????
{
39
????????
return
?a.name;
40
????}
41
42
????
public
?String?name;
43
44
????
private
?
int
?age;
45
46
????
public
?AAA?birthday;
47
48
????
public
?Object?clone()
49
????
{
50
????????
try
51
????????
{
52
????????????
super
.clone();
53
????????????
return
?
super
.clone();
54
????????}
?
catch
?(Exception?e)
55
????????
{
56
????????????
return
?
null
;
57
????????}
58
????}
59
}
60
61
public
?
class
?TestClone
62
{
63
????
public
?
static
?
void
?main(String[]?args)
64
????
{
65
????????AAA?Day?
=
?
new
?AAA(
"
test
"
);
66
????????DOG?dog1?
=
?
new
?DOG(
"
xiaogou
"
,?
2
,?Day);
67
????????DOG?dog2?
=
?(DOG)?dog1.clone();
68
????????
//
dog2.birthday?=?(AAA)?dog1.birthday.clone();
69
????????dog1.birthday.name?
=
?
"
333
"
;
70
????????System.out.println(dog1.getBirth(dog1.birthday));
71
????????System.out.println(dog2.getBirth(dog2.birthday));
72
????}
73
}
74
75
class
?SerialCloneable?
implements
?Cloneable,?Serializable
76
{
77
????
public
?Object?clone()
78
????
{
79
????????
try
80
????????
{
81
????????????ByteArrayOutputStream?bout?
=
?
new
?ByteArrayOutputStream();
82
????????????ObjectOutputStream?out?
=
?
new
?ObjectOutputStream(bout);
83
????????????out.writeObject(
this
);
84
????????????out.close();
85
????????????ByteArrayInputStream?bin?
=
?
new
?ByteArrayInputStream(bout
86
????????????????????.toByteArray());
87
????????????ObjectInputStream?in?
=
?
new
?ObjectInputStream(bin);
88
????????????Object?ret?
=
?in.readObject();
89
????????????in.close();
90
????????????
return
?ret;
91
????????}
?
catch
?(Exception?e)
92
????????
{
93
????????????
return
?
null
;
94
????????}
95
????}
96
}
97
輸出:
333
test
上面的代碼用序列化與反序列化實現了對象拷貝。比較通用。但是得注意的是其中的類得implements Serializable。
?
3)后記
我們如果利用強大的反射機制+序列化與反序列化,能做出更加靈活的對象拷貝。有興趣的朋友可以自行去研究。
我在javaeye上看到一篇短文:http://www.javaeye.com/post/367014 主要講的就是反射在對象拷貝中的應用。
?
posted on 2008-04-28 11:52
-274°C 閱讀(10462)
評論(6) 編輯 收藏 所屬分類:
JAVA