• 多态


    本篇讲解实现多态的三种方法:虚方法、抽象方法和接口。

    人类都能说话,但是不同国家的人可能使用的语言不一样,所以,不同国家的人说同样的话,会有不同的表现形式(同一事情,不同表现形态),如何用程序体现这种差异呢?

     1  class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Person[] ps = new Person[5];
     6             ps[0] = new Chinese();
     7             ps[1] = new British();
     8             ps[2] = new Japanese();
     9 
    10             for (int i = 0; i < ps.Length; i++)
    11             {
    12                 if (ps[i] is Chinese)
    13                 {
    14                     Chinese c=(Chinese)ps[i];
    15                     c.Introduce();
    16                 }
    17 
    18                 if (ps[i] is British)
    19                 {
    20                     British c = (British)ps[i];
    21                     c.Introduce();
    22                 }
    23 
    24                 if (ps[i] is Japanese)
    25                 {
    26                     Japanese c = (Japanese)ps[i];
    27                     c.Introduce();
    28                 }
    29             }
    30 
    31             Console.ReadKey();
    32         }
    33     }
    34 
    35     public class Person
    36     {
    37         public string Name { get; set; }
    38     }
    39 
    40     public class Chinese:Person
    41     {
    42         public void Introduce()
    43         {
    44             Console.WriteLine("我是中国人");
    45         }
    46     }
    47 
    48     public class British : Person
    49     {
    50         public void Introduce()
    51         {
    52             Console.WriteLine("我是英国人");
    53         }
    54     }
    55 
    56     public class Japanese : Person
    57     {
    58         public void Introduce()
    59         {
    60             Console.WriteLine("我是日本人");
    61         }
    62     }
    View Code

    上面的代码能体现这种差异,但是会留下其他问题。1.for循环中的if判断会随着数组中的元素增加而增多。2.数组增加一个元素就需要改动以前的代码(添加if判断),违背了程序的开闭原则(对扩展开放,对修改关闭)。如果用虚方法就能避免这个问题。

    一、虚方法

    下面是虚方法的代码:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Person[] ps = new Person[3];
     6             ps[0] = new Chinese();
     7             ps[1] = new British();
     8             ps[2] = new Japanese();
     9 
    10             for (int i = 0; i < ps.Length; i++)
    11             {
    12                 //if (ps[i] is Chinese)
    13                 //{
    14                 //    Chinese c=(Chinese)ps[i];
    15                 //    c.Introduce();
    16                 //}
    17 
    18                 //if (ps[i] is British)
    19                 //{
    20                 //    British c = (British)ps[i];
    21                 //    c.Introduce();
    22                 //}
    23 
    24                 //if (ps[i] is Japanese)
    25                 //{
    26                 //    Japanese c = (Japanese)ps[i];
    27                 //    c.Introduce();
    28                 //}
    29 
    30                 ps[i].Introduce();//调用同一个方法,输出不同的结果。对同一事情,作出不同的反应。
    31             }
    32 
    33             Console.ReadKey();
    34         }
    35     }
    36 
    37     public class Person
    38     {
    39         public string Name { get; set; }
    40 
    41         public virtual void Introduce()
    42         {
    43             Console.WriteLine("我是中国人");
    44         }
    45     }
    46 
    47     public class Chinese:Person
    48     {
    49         public override void Introduce()
    50         {
    51             Console.WriteLine("我是中国人");
    52         }
    53     }
    54 
    55     public class British : Person
    56     {
    57         public override void Introduce()
    58         {
    59             Console.WriteLine("我是英国人");
    60         }
    61     }
    62 
    63     public class Japanese : Person
    64     {
    65         public override void Introduce()
    66         {
    67             Console.WriteLine("我是日本人");
    68         }
    69     }
    View Code

    用虚方法能避免上面的两个问题。

    注意:

    1.虚方法的两个关键字:virtual和override。

    2.虚方法可以重新,也可以不重写。如果子类有与父类虚方法重名方法,但是又想说明这个方法不是重写的方法,可以加new关键字。

    3.用虚方法实现多态后,父类变量传入子类对象,父类变量调用的方法都是父类中已有的方法,只不过实现的方式不一样。如果子类没有重写虚方法(子类中没有显式的写这个方法),此时调用的方法也可以理解为是子类中的,(子类继承父类的),只不过没有显示。

     积累:

    object 中有ToString(),因为所有的类都继承类object,所以所有的类都有ToString()方法。但是不同的类调用ToString后的结果不同,这取决于这个类中的ToString()方法是怎么实现的。如:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             object obj = new object();
     6             Console.WriteLine(obj.ToString());
     7 
     8             string[] names = new string[] { "a","b","c"};
     9 
    10             Console.WriteLine(names.ToString());
    11 
    12             string agrs = new string(new char[] { 'a', 'b', 'c' });
    13             Console.WriteLine(agrs.ToString());
    14 
    15             int a = 12;
    16             Console.WriteLine(a.ToString());
    17 
    18             Console.ReadKey();
    19         }
    20     }
    View Code

    输出的结果依次是:System.Object,System.String[],abc,12。反编译后发现,前面两种类型的ToString()方法中是返回this.GetType().ToString().后两者返回的结果最终都是this,即当前对象。

    二、抽象方法

    用抽象方法实现文章开头的问题的代码:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             Person[] ps = new Person[2];
     6             ps[0] = new Chinese();
     7             ps[1] = new Japanese();
     8 
     9             for (int i = 0; i < ps.Length; i++)
    10             {
    11                 ps[i].Introduce();
    12             }
    13 
    14             Console.ReadKey();
    15         }
    16     }
    17 
    18     public abstract class Person
    19     {
    20         public abstract void Introduce();
    21     }
    22 
    23     public class Chinese : Person
    24     {
    25         public override void Introduce()
    26         {
    27             Console.WriteLine("我是中国人");
    28         }
    29     }
    30 
    31     public class Japanese : Person
    32     {
    33         public override void Introduce()
    34         {
    35             Console.WriteLine("我是日本人!");
    36         }
    37     }
    View Code

    用虚方法和用抽象方法实现多态的区别

    1.虚方法必须有方法体,抽象方法没有。

    2.子类可以实现虚方法,也可以不实现。但是抽象方法必须实现(除非子类也是抽象类 )。可见,用抽象方法实现多态,父类对子类控制得更严格。

    虚方法和抽象方法实现多态的场景

    1.如果子类的实现方式都不一样,那么父类就没必要存在方法体,考虑用抽象方法。

    2.如果父类没必要实例化,考虑用抽象方法。

    三、接口

    1.接口是一种规范,是一种能力。

    2.接口中只能包含方法(属性,事件,索引本质上都是方法)

    3.能实现多态,代码如下:

     1 class Program
     2     {
     3         static void Main(string[] args)
     4         {
     5             IFlyable supperMan = new SupperMan();
     6             supperMan.Fly();
     7             IFlyable spiderMan = new SpiderMan();
     8             spiderMan.Fly();
     9             Console.ReadKey();
    10         }
    11     }
    12 
    13     public interface IFlyable
    14     {
    15         void Fly();
    16     }
    17 
    18     public class SupperMan : IFlyable
    19     {
    20         public void Fly()
    21         {
    22             Console.WriteLine("超人会飞……");
    23         }
    24     }
    25 
    26     public class SpiderMan : IFlyable
    27     {
    28         public void Fly()
    29         {
    30             Console.WriteLine("蜘蛛侠也会飞……");
    31         }
    32     }
    View Code

    上面的代码可用抽象方法实现,为何还用接口实现?如果现在我再加个鸟类,也实现了飞的方法,但是鸟,蜘蛛侠,超人却无法抽象出一个父类,此时可以考虑用接口达到这个目的。

    总结:

    虚方法,抽象方法,接口都能实现多态,那各自的应用场景是什么呢?

    1.虚方法中的方法必须有方法体,子类可以实现。

    2.抽象方法不用实现,子类必须显式的实现。当子类的相同动作,实现的方式不同的时候,可以在父类中定义抽象方法(因为父类不用实现,事实上父类中的方法也不知道怎么实现)。当然也可以用接口。

    3.当多个类都需要实现某个动作,但是这几个类却无法抽象出一个共同的父类的时候,可以用接口实现。类可以实现多个接口,但是只能继承一个父类,接口可以解决继承的单根性问题。

  • 相关阅读:
    Spring依赖注入的方式、类型、Bean的作用域、自动注入、在Spring配置文件中引入属性文件
    RESTful风格、异常处理、Spring框架
    文件上传、数据校验(后台)、拦截器
    接收的参数为日期类型、controller控制层进行数据保存、进行重定向跳转
    SpringMVC入门Demo
    Mybatis入门Demo(单表的增删改查)
    Spring
    spring的exception
    restful风格
    Java后台验证
  • 原文地址:https://www.cnblogs.com/wesley168/p/6382486.html
Copyright © 2020-2023  润新知