大話深入淺出Effective Java核心實戰編程思想之——猴王的把戲
不知道大家還記不記得在《西游記》里的蓮花洞奪寶的故事,就是猴王巧奪寶物,收復金銀角大王那一章。到底這個故事給了我們什么啟示呢?這故事又和Effective Java有什么聯系?還是延續上篇文章的風格吧,看代碼,讀故事。

看到這里你應該對深克隆和淺克隆有了初步的了解了吧?現在我們再看怎樣深克隆一個猴王,哦,不對,應該是真正猴王的七十二變。(為什么我叫他猴王,因為孫悟空有歧義)。
程序員的一生其實可短暫了,這電腦一開一關,一天過去了,嚎;電腦一開不關,那就成服務器了,嚎……

1
import static org.junit.Assert.*;
2
import org.junit.Test;
3
4
5
public class TestClone {
6
7
@Test
8
public void testClone(){
9
// 西天取經的路上,金角大王和銀角大王把唐僧抓走了
10
猴王 齊天大圣=new 猴王("齊天大圣孫悟空");
11
//大圣手拿金箍棒,正要收拾金、銀角大王。
12
齊天大圣.取得武器(new 金箍棒());
13
14
/*
15
* 這時候,金角大王和銀角大王聽聞大圣來者不善,立馬讓小妖去請出他們的寶葫蘆
16
* 當然這一切瞞不過神通廣大的大圣爺。大圣猴毛一吹,變出一個老道士。
17
*/
18
猴王 空悟孫道士=(猴王)齊天大圣.變出一個化身();
19
空悟孫道士.改名("空悟孫道士");
20
21
/*
22
* 老道士忽悠小妖說他的葫蘆更厲害,能把天都給收了,智力值只有20的小妖看了羨慕不已,要求交換葫蘆。
23
* 老道士自然很樂意,換了葫蘆,直奔妖怪洞穴,收服了金、銀角大王。
24
*/
25
空悟孫道士.取得武器(new 寶葫蘆());
26
27
//問題1:道士拿的是什么武器?道士是由大圣克隆而來,拿的卻不是金箍棒,而是寶葫蘆?
28
assertFalse(齊天大圣.的武器() instanceof 金箍棒);
29
assertTrue(空悟孫道士.的武器() instanceof 寶葫蘆);
30
31
//問題2:大圣和道士拿同一個武器?
32
assertSame(空悟孫道士.的武器(),齊天大圣.的武器());
33
34
//問題3:既然武器是一樣的,為什么名字又不一樣呢?
35
assertEquals(齊天大圣.名字(),"齊天大圣孫悟空");
36
assertEquals(空悟孫道士.名字(),"空悟孫道士");
37
38
/*
39
* 答案:猴王類繼承了Object.clone(),其克隆原理是:如果類每個域包含一個原語類型(primitive)的值,
40
* 或者包含一個指向非可變(final)對象的引用,那么返回的值或對象是一個相同的拷貝;否則,如果是可變類,則會返回相同的引用。
41
* 因為金箍棒類不是非可變類,而String是,所以你應該明白,為什么大圣爺和他的克隆體有不同的名字,卻有相同的武器吧。
42
*
43
* Object.clone()被稱為淺拷貝,或淺克隆。相對應的是深克?。╠eep clone),他是指類在克隆時也拷貝可變對象。
44
* 看到這里你應該知道其實這個猴王類實現得不合理,他應該擁有一個深克隆的方法。
45
*/
46
}
47
48
class 猴王 implements Cloneable{
49
private String name;
50
private 武器[] weapon=new 武器[1];
51
52
public 猴王(String name){
53
this.name=name;
54
}
55
56
/**
57
* 取得一個猴王的淺克隆化身
58
* @return
59
*/
60
public Object 變出一個化身(){
61
Object cloneObj=null;
62
try{
63
cloneObj=clone();
64
}catch(CloneNotSupportedException ex){
65
ex.printStackTrace();
66
}
67
return cloneObj;
68
}
69
70
@Override
71
protected Object clone() throws CloneNotSupportedException{
72
return super.clone();
73
}
74
75
public String 名字() {
76
return name;
77
}
78
79
public void 改名(String name){
80
this.name=name;
81
}
82
83
public 武器 的武器() {
84
return weapon[0];
85
}
86
87
public void 取得武器(武器 weapon) {
88
this.weapon[0] = weapon;
89
}
90
}
91
92
class 武器{
93
public 武器(){
94
95
}
96
}
97
98
class 金箍棒 extends 武器{
99
public 金箍棒(){
100
}
101
}
102
103
class 寶葫蘆 extends 武器{
104
public 寶葫蘆(){
105
}
106
}
107
108
109
}
110

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

看到這里你應該對深克隆和淺克隆有了初步的了解了吧?現在我們再看怎樣深克隆一個猴王,哦,不對,應該是真正猴王的七十二變。(為什么我叫他猴王,因為孫悟空有歧義)。
1
import static org.junit.Assert.assertEquals;
2
import static org.junit.Assert.assertFalse;
3
import static org.junit.Assert.assertNotSame;
4
import static org.junit.Assert.assertTrue;
5
6
import org.junit.Test;
7
8
9
public class TestDeepClone {
10
11
@Test
12
public void testDeepClone(){
13
// 西天取經的路上,金角大王和銀角大王把唐僧抓走了
14
猴王 齊天大圣=new 猴王("齊天大圣孫悟空");
15
//大圣手拿金箍棒,正要收拾金、銀角大王。
16
齊天大圣.取得武器(new 金箍棒());
17
18
/*
19
* 這時候,金角大王和銀角大王聽聞大圣來者不善,立馬讓小妖去請出他們的寶葫蘆
20
* 當然這一切瞞不過神通廣大的大圣爺。大圣猴毛一吹,變出一個老道士。
21
*/
22
猴王 空悟孫道士=(猴王)齊天大圣.變出一個化身();
23
空悟孫道士.改名("空悟孫道士");
24
25
/*
26
* 老道士忽悠小妖說他的葫蘆更厲害,能把天都給收了,智力值只有20的小妖看了羨慕不已,要求交換葫蘆。
27
* 老道士自然很樂意,換了葫蘆,直奔妖怪洞穴,收服了金、銀角大王。
28
*/
29
齊天大圣.取得武器(new 寶葫蘆());
30
31
32
assertTrue(空悟孫道士.的武器() instanceof 金箍棒);
33
assertFalse(空悟孫道士.的武器() instanceof 寶葫蘆);
34
assertNotSame(空悟孫道士.的武器(),齊天大圣.的武器());
35
assertEquals(齊天大圣.名字(),"齊天大圣孫悟空");
36
assertEquals(空悟孫道士.名字(),"空悟孫道士");
37
}
38
39
class 猴王 implements Cloneable{
40
private String name;
41
private 武器 weapon;
42
43
public 猴王(String name){
44
this.name=name;
45
}
46
47
/**
48
* 取得一個猴王的淺克隆化身
49
* @return
50
*/
51
public Object 變出一個化身(){
52
Object cloneObj=null;
53
try{
54
cloneObj=clone();
55
}catch(CloneNotSupportedException ex){
56
ex.printStackTrace();
57
}
58
return cloneObj;
59
}
60
61
/**
62
* 取得一個猴王的深克隆化身
63
* @return
64
*/
65
public Object 變出一個新化身(){
66
Object cloneObj=null;
67
try{
68
cloneObj=clone();
69
}catch(CloneNotSupportedException ex){
70
ex.printStackTrace();
71
}
72
return cloneObj;
73
}
74
75
@Override
76
protected Object clone() throws CloneNotSupportedException{
77
return super.clone();
78
}
79
80
public String 名字() {
81
return name;
82
}
83
84
public void 改名(String name){
85
this.name=name;
86
}
87
88
public 武器 的武器() {
89
return weapon;
90
}
91
92
public void 取得武器(武器 weapon) {
93
this.weapon = weapon;
94
}
95
}
96
97
abstract class 武器 implements Cloneable{
98
public 武器(){
99
100
}
101
102
@Override
103
public Object clone(){
104
Object result=null;
105
try{
106
result= super.clone();
107
}catch(CloneNotSupportedException ex){
108
ex.printStackTrace();
109
}
110
return result;
111
}
112
}
113
114
class 金箍棒 extends 武器{
115
public 金箍棒(){
116
}
117
118
@Override
119
public Object clone(){
120
return super.clone();
121
}
122
}
123
124
class 寶葫蘆 extends 武器{
125
public 寶葫蘆(){
126
}
127
128
@Override
129
public Object clone(){
130
return super.clone();
131
}
132
}
133
}
134

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

程序員的一生其實可短暫了,這電腦一開一關,一天過去了,嚎;電腦一開不關,那就成服務器了,嚎……
posted on 2009-07-04 14:37 Heis 閱讀(1736) 評論(4) 編輯 收藏 所屬分類: Effective Java