zoukankan      html  css  js  c++  java
  • 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引用指向的是哪一个扩展类的对象?

          (待续)

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

  • 相关阅读:
    Hadoop之HDFS的热备份
    Hadoop之联邦HDFS
    Hadoop之HDFS如何保证高可用
    Hadoop之HDFS的读流程
    Hadoop之HDFS数据写流程和写失败的情况
    Hadoop之HDFS的block、packet、chunk
    Hadoop之HDFS的元数据冷备份(CheckPoint)
    当ZooKeeper作为Dubbo的注册中心的时候,是怎么工作的?
    Dubbo
    mysql磁盘满了如何恢复
  • 原文地址:https://www.cnblogs.com/allenzheng/p/2760267.html
Copyright © 2011-2022 走看看