zoukankan      html  css  js  c++  java
  • 【C#小知识】C#中一些易混淆概念总结(八)---------解析接口

    这一篇主要来解析关于面向对象中最总要的一个概念——接口。 

    对于接口来说,C#是有规定使用Interface关键字来声明接口。它的声明是和类一致的。可以说接口就是一个特殊的抽象类。如下代码:

    class Program
        {
            static void Main(string[] args)
            {
            }
        }
    
        //声明一个可以飞的接口
        interface IRunable
        {
            //包含可以被继承的子类实现的方法
            void Run();
        }


    由以前的抽象类的知识可以知道,抽象类是没有办法实例化的(因为含有抽象成员,而抽象成员不含有方法体)。那么接口可不可以实例化呢?答案是肯定的,不能实例化。看下面的一段代码:

    这个时候编译器告诉我们无法创建抽象类或者接口的实例。

    二,接口可以定义哪些成员

    1)接口就是一个定义“具有某种能力的抽象类”,既然接口是类,那么它的内部可以定义哪些成员呢?

    首先,在普通的类中,可以有字段,属性,方法,索引器,抽象方法等等。那么接口呢?

    看下面直接声明字段,编译器会报错,告诉我们接口内不能声明字段

    既然接口内不能有字段,那也就不存在封装字段了。所以上边图示的封装字段的代码也是错误的。

    同理由上面的代码也可以知道,在接口中是不可以定义显式的属性(因为在属性中要操作字段赋值,但是字段没有办法在接口中声明)。

    那么接口可以声明自动属性么?看下面的代码:

     //声明一个可以飞的接口
        interface IRunable
        {
            //声明字段
            int nAge { get; set; }
           
            string strName { get; set; }
            ////包含可以被继承的子类实现的方法
            void Run();
    
        }

    代码可以顺利编译通过,那么是为什么呢?这就要看.NET的源码,我把源码编译后的比较结果如下图:

     

    抽象方法就不用多了,本来接口就是一个抽象爱类,当然可以定义抽象类,但是不在使用abstract关键字,而且方法必须没有方法体;

    2)继承接口的子类必须实现接口的所有抽象成员。

     我们先来看下面的代码:

     //声明一个接口,其中包含属性和未实现方法void
        interface IRunable
        {
            string strName { get; set; }
            void Run();
        }

    下面来一个实现类,如下:

     class Person:IRunable
        {
           public  void Run()
            {
                Console.WriteLine("我可以奔跑!");
            }
        }

    这时候,我们编译,编译器会告诉我们什么呢?如下图:

     

     所以继承接口的类,必须实现接口的所有抽象成员。

    正确的代码如下:

     class Person:IRunable
        {
           public  void Run()
            {
                Console.WriteLine("我可以奔跑!");
            }
    
           public string strName
           {
               get
               {
                   return strName;
               }
               set
               {
                   strName = value;
               }
           }
        }


    通过以上的代码可以发现:

    ①我们的继承类在实现接口成员的时候不需要使用override关键字

    ②实现接口的时候,必须保持签名一致

     

    由前面抽象类的知识我们有没有这样的疑问,什么时候使用抽象类,什么时候使用接口呢?

    总结如下:

    ①使用抽象类:可以找到父类,并且希望通过父类继承给子类一些成员

    ②使用接口:接口就是一个纯粹的为了规范实现的类。比如:多个类具有相同的方法,但是却找不到父类,就可以将方法定义在接口中。让这些类去实现。

    下面纠纷别来看两端代码,比较抽象类和接口的异同,首先是抽象类:

     

    class Program
        {
            static void Main(string[] args)
            {
                Student s = new Student();
                //Student类通过继承获得NAge属性
                s.NAge = 10;
                s.Eat();
    
                Console.WriteLine("--------Student和Worker类分别通过继承获得了父类的非私有成员,实现了父类的抽象方法--------");
    
                Worker w = new Worker();
                //Worker类通过继承获得NAge属性
                w.NAge = 40;
                w.Eat();
    
                Console.ReadKey();
            }
        }
    
        //定义父类
        abstract class Person
        {
           private int nAge;
    
            public int NAge
            {
                get { return nAge; }
                set { nAge = value; }
            }
           
            private void Run()
            {
                Console.WriteLine("我是父类,我可以跑!");
            }
            public abstract void Eat();
    
        }
    
        class Student : Person
        {
            //子类覆写了父类的抽象方法
            public override void Eat()
            {
                Console.WriteLine("我是子类,我继承了父类,我可以在学校吃饭!");
            }
        }
    
        class Worker:Person
        {
            //同样Worker也通过继承获得了父类的非私有成员
            public override void Eat()
            {
                Console.WriteLine("我是子类,我继承父类,我可以在工厂吃饭");
            }
        }


    接下来,来看看接口是怎么规范多个类的实现的。

    class Program
        {
            static void Main(string[] args)
            {
                Student s = new Student();
                s.strName = "小学生";
                s.Run();
                Console.WriteLine(s.strName);
                Console.WriteLine("--------------------");
                Worker w = new Worker();
                w.strName = "看我能不能渎职";
                w.Run();
                Console.WriteLine(w.strName);
    
                Console.ReadKey();
            }
        }
    
        interface IRunable
        {
            //规范子类必须实现strName属性
            string strName { get; set; }
            //规范子类必须实现Run()方法
            void Run();
    
        }
    
        class Student:IRunable
        {
            //这里是子类的字段
            string strname;
            public string strName
            {
                get
                {
                    return strname;
                }
                set
                {
                    strname = value;
                }
            }
    
            public void Run()
            {
                Console.WriteLine("我是小学生,我在学校里面跑步!");
            }
    
          
        }
    
        class Worker:IRunable
        {
            string strname;
            public string strName
            {
                get
                {
                    return "工人";
                }
                set
                {
                    strname = value;
                }
            }
    
            public void Run()
            {
                Console.WriteLine(  "我是工人,我需要在厂区跑!");
            }
        }

    由以上的代码可不可以发现,接口仅仅在规定一个规范子类的实现,而抽象类可以通过继承,继承给子类某些成员。

    最后来看一下,接口的显示实现,我先看接口的普通实现(以上的代码实现接口的方式都是隐式实现)

    interface IRunable
        {
            //规范子类必须实现strName属性
            string strName { get; set; }
            //规范子类必须实现Run()方法
            void Run();
    
        }
    
        class Student:IRunable
        {
            //这里是子类的字段
            string strname;
            public string strName
            {
                get
                {
                    return strname;
                }
                set
                {
                    strname = value;
                }
            }
    
            public void Run()
            {
                Console.WriteLine("我是小学生,我在学校里面跑步!");
            }
    
    
        }


    显式实现接口

     class Student:IRunable
        {
            //这里是子类的字段
            string strname;
            //显示实现接口
            string IRunable.strName
            {
                get
                {
                    return strname;
                }
                set
                {
                    strname = value;
                }
            }
    
            void IRunable.Run()
            {
                Console.WriteLine("我是小学生,我在学校里面跑步!");
            }
    
        }


    显示的实现接口是为了解决方法名冲突的问题。但是显示实现接口会出现,在上面的代码中会出现一个问题,如下图:

    为什么会这样呢?

    因为显式实现接口的方法是私有的,不能通过对象变量来调用。那应该怎么调用呢,看下面的代码:

    class Program
        {
            static void Main(string[] args)
            {
               
    
                //里氏替换原则,父类变量指向子类对象,并通过父类变量调用子类方法
                IRunable ir = new Student();
                ir.Run();
                Console.ReadKey();
            }
        }
    
        interface IRunable
        {
            //规范子类必须实现strName属性
            string strName { get; set; }
            //规范子类必须实现Run()方法
            void Run();
    
        }
    
        class Student:IRunable
        {
            //这里是子类的字段
            string strname;
            //显示实现接口
            string IRunable.strName
            {
                get
                {
                    return strname;
                }
                set
                {
                    strname = value;
                }
            }
    
            void IRunable.Run()
            {
                Console.WriteLine("我是小学生,我在学校里面跑步!");
            }
    
           // Student s = new Student();
          
    
        }

    打印结果如下:

    显式实现接口,这个接口的方法,只能通过接口变量来调用。

    接口导图总结如下:

     

  • 相关阅读:
    sqlserver中判断表或临时表是否存在
    Delphi 简单方法搜索定位TreeView项
    hdu 2010 水仙花数
    hdu 1061 Rightmost Digit
    hdu 2041 超级楼梯
    hdu 2012 素数判定
    hdu 1425 sort
    hdu 1071 The area
    hdu 1005 Number Sequence
    hdu 1021 Fibonacci Again
  • 原文地址:https://www.cnblogs.com/yisuowushinian/p/3552007.html
Copyright © 2011-2022 走看看