Java为何需要多态机制?

     先看一个程序代码,我们通过该程序多方面揣摩Java设计者设计多态机制的由来。

 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 /*输出结果:

72 

73 Wind.play() MIDDLE_C

74 

75 */

      对于以上这个例子我们可以看出,由于Wind类从Instrument类继承而来,而在Java中支持向上转型(对象既可以作为它自己本身的类型使用,也可以作为它的基类型使用,这种在把对某个对象的引用视为对其基类的引用的做法称为向上转型——因为在继承树的画法中,基类是放置在上方的),理所当然当一个Wind引用传递到tune()方法时,不需要任何类型转换,这样Wind引用flute通过调用Wind的方法play(),输出结果:Wind.play() MIDDLE_C。

      然而Music.java看起来似乎有些奇怪,为何所有人都故意忘记对象的类型?而要让其进行向上转型?这有违常规行为,如果让tune()方法直接接受一个Wind引用作为自己的参数,似乎会更为直观。这样的想法很直接,但这样会引发一个重要的问题:如果那样做就要为系统里的每一个Instrument类的子类都编写一个新的方法。假设按照这种推理,现在再加入StringedBrass这两种乐器,则代码如下:

 

  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 /*输出结果:

116 

117 Wind.play() MIDDLE_C

118 

119 Stringed.play() MIDDLE_C

120 

121 Brass.play() MIDDLE_C

122 

123 */

      由上述例子的输出结果可以知道,这样做也行得通,但有一个缺点:必须为添加的每一个Instrument类的子类编写特定类型的tune()方法,这意味着需要编写更多的代码,而且如果以后每添加一个由Instrument导出的类就要在Music.java中重载一个tune()方法,这无疑提高了程序员的工作量。此外,如果我们忘记重载某个方法,编译器不会返回任何错误信息,这样关于类型的整个处理过程就显得难以操纵。

      面对如此困境,我们急需一种更高明的方法去解决这一问题。如果运用多态,则很容易实现,相关代码如下:

  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 /*输出结果:

 98 

 99 Wind.play() MIDDLE_C

100 

101 Stringed.play() MIDDLE_C

102 

103 Brass.play() MIDDLE_C

104 

105 */

      这样看起来代码是不是精简多了呢?这里就用到了Java的多态。在Java多态中,由于Java支持扩展类向上转型当成基类使用,不管导出类的存在,编写的代码只是与基类打交道。而这正是我们想要的结果。

      这又让我们对多态的运作方式很是迷惑,究竟这种多态机制是如何实现的?凭什么允许我们这么做?在上例中编译器怎么知道Instrument引用指向的是哪一个扩展类的对象?

      (待续)

 

         以上所述若有不妥,欢迎拍砖!

你可能感兴趣的:(java)