Java为何需要多态机制?
先看一個程序代碼,我們通過該程序多方面揣摩Java設(shè)計者設(shè)計多態(tài)機制的由來。
1 //:polymorphism/music/Note.java
2
3 package polymorphism.music;
4
5 public ennum Note{
6
7 MIDDLE_C,C_SHARP,B_FLAT;
8
9 }
10
11
12
13 //:polymorphism/music/Instrument.java
14
15 package polymorphism.music;
16
17 Class Instrument{
18
19 public void play(Note n){
20
21 System.out.print("Instrument.play()");
22
23 }
24
25 }
26
27
28
29 //:polymorphism/music/Wind.java
30
31 package polymorphism.music;
32
33 public class Wind extends Instrument{
34
35 public void play(Note n){
36
37 System.out.print("Wind.play()"+n);
38
39 }
40
41 }
42
43
44
45 //:polymorphism/music/ Music.java
46
47 package polymorphism.music;
48
49 public class Music{
50
51 public static void tune(Instrument i){
52
53 i.play(Note.MIDDLE_C);
54
55 }
56
57
58
59 public static void main(String args[]){
60
61 Wind flute=new Wind();
62
63 tune(flute);
64
65 }
66
67 }
68
69
70
71 /*輸出結(jié)果:
72
73 Wind.play() MIDDLE_C
74
75 */
對于以上這個例子我們可以看出,由于Wind類從Instrument類繼承而來,而在Java中支持向上轉(zhuǎn)型(對象既可以作為它自己本身的類型使用,也可以作為它的基類型使用,這種在把對某個對象的引用視為對其基類的引用的做法稱為向上轉(zhuǎn)型——因為在繼承樹的畫法中,基類是放置在上方的),理所當(dāng)然當(dāng)一個Wind引用傳遞到tune()方法時,不需要任何類型轉(zhuǎn)換,這樣Wind引用flute通過調(diào)用Wind的方法play(),輸出結(jié)果:Wind.play() MIDDLE_C。
然而Music.java看起來似乎有些奇怪,為何所有人都故意忘記對象的類型?而要讓其進行向上轉(zhuǎn)型?這有違常規(guī)行為,如果讓tune()方法直接接受一個Wind引用作為自己的參數(shù),似乎會更為直觀。這樣的想法很直接,但這樣會引發(fā)一個重要的問題:如果那樣做就要為系統(tǒng)里的每一個Instrument類的子類都編寫一個新的方法。假設(shè)按照這種推理,現(xiàn)在再加入Stringed和Brass這兩種樂器,則代碼如下:
1 //:polymorphism/music/Note.java
2
3 package polymorphism.music;
4
5 public ennum Note{
6
7 MIDDLE_C,C_SHARP,B_FLAT;
8
9 }
10
11
12
13 //:polymorphism/music/Instrument.java
14
15 package polymorphism.music;
16
17 Class Instrument{
18
19 public void play(Note n){
20
21 System.out.println("Instrument.play()");
22
23 }
24
25 }
26
27
28
29 //:polymorphism/music/Wind.java
30
31 package polymorphism.music;
32
33 public class Wind extends Instrument{
34
35 public void play(Note n){
36
37 System.out.println("Wind.play()"+n);
38
39 }
40
41 }
42
43
44
45 // package polymorphism.music;
46
47 public class Stringed extends Instrument{
48
49 public void play(Note n){
50
51 System.out.println("Stringed.play()"+n);
52
53 }
54
55 }
56
57
58
59 // package polymorphism.music;
60
61 public class Brass extends Instrument{
62
63 public void play(Note n){
64
65 System.out.println("Brass.play()"+n);
66
67 }
68
69 }
70
71
72
73 //:polymorphism/music/ Music.java
74
75 package polymorphism.music;
76
77 public class Music{
78
79 public static void tune(Wind i){
80
81 i.play(Note.MIDDLE_C);
82
83 }
84
85 public static void tune(Stringed i){
86
87 i.play(Note.MIDDLE_C);
88
89 }
90
91 public static void tune(Brass i){
92
93 i.play(Note.MIDDLE_C);
94
95 }
96
97 public static void main(String args[]){
98
99 Wind flute=new Wind();
100
101 Stringed violin=new Stringed();
102
103 Brass frenchHorn =new Brass();
104
105 tune(flute);
106
107 tune(violin);
108
109 tune(frenchHorn);
110
111 }
112
113 }
114
115 /*輸出結(jié)果:
116
117 Wind.play() MIDDLE_C
118
119 Stringed.play() MIDDLE_C
120
121 Brass.play() MIDDLE_C
122
123 */
由上述例子的輸出結(jié)果可以知道,這樣做也行得通,但有一個缺點:必須為添加的每一個Instrument類的子類編寫特定類型的tune()方法,這意味著需要編寫更多的代碼,而且如果以后每添加一個由Instrument導(dǎo)出的類就要在Music.java中重載一個tune()方法,這無疑提高了程序員的工作量。此外,如果我們忘記重載某個方法,編譯器不會返回任何錯誤信息,這樣關(guān)于類型的整個處理過程就顯得難以操縱。
面對如此困境,我們急需一種更高明的方法去解決這一問題。如果運用多態(tài),則很容易實現(xiàn),相關(guān)代碼如下:
1 //:polymorphism/music/Note.java
2
3 package polymorphism.music;
4
5 public ennum Note{
6
7 MIDDLE_C,C_SHARP,B_FLAT;
8
9 }
10
11
12
13 //:polymorphism/music/Instrument.java
14
15 package polymorphism.music;
16
17 Class Instrument{
18
19 public void play(Note n){
20
21 System.out.println("Instrument.play()");
22
23 }
24
25 }
26
27
28
29 //:polymorphism/music/Wind.java
30
31 package polymorphism.music;
32
33 public class Wind extends Instrument{
34
35 public void play(Note n){
36
37 System.out.println("Wind.play()"+n);
38
39 }
40
41 }
42
43
44
45 // package polymorphism.music;
46
47 public class Stringed extends Instrument{
48
49 public void play(Note n){
50
51 System.out.println("Stringed.play()"+n);
52
53 }
54
55 }
56
57
58
59 // package polymorphism.music;
60
61 public class Brass extends Instrument{
62
63 public void play(Note n){
64
65 System.out.println("Brass.play()"+n);
66
67 }
68
69 }
70
71
72
73 //:polymorphism/music/ Music.java
74
75 package polymorphism.music;
76
77 public class Music{
78
79 public static void main(String args[]){
80
81 Instrument flute=new Wind();
82
83 Instrument violin=new Stringed();
84
85 Instrument frenchHorn =new Brass();
86
87 flute.play(Note. MIDDLE_C);
88
89 violin.play(Note. MIDDLE_C);
90
91 frenchHorn.play(Note. MIDDLE_C);
92
93 }
94
95 }
96
97 /*輸出結(jié)果:
98
99 Wind.play() MIDDLE_C
100
101 Stringed.play() MIDDLE_C
102
103 Brass.play() MIDDLE_C
104
105 */
這樣看起來代碼是不是精簡多了呢?這里就用到了Java的多態(tài)。在Java多態(tài)中,由于Java支持?jǐn)U展類向上轉(zhuǎn)型當(dāng)成基類使用,不管導(dǎo)出類的存在,編寫的代碼只是與基類打交道。而這正是我們想要的結(jié)果。
這又讓我們對多態(tài)的運作方式很是迷惑,究竟這種多態(tài)機制是如何實現(xiàn)的?憑什么允許我們這么做?在上例中編譯器怎么知道Instrument引用指向的是哪一個擴展類的對象?
(待續(xù))
以上所述若有不妥,歡迎拍磚!
總結(jié)
以上是生活随笔為你收集整理的Java为何需要多态机制?的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: iPhone 11 底部扬声器只有一边有
- 下一篇: CTE的使用