第三章:继承/抽象类/接口

继承

在面向对象编程中,有两种截然不同的继承类型,实现继承和接口继承;C#中不支持多重继承,C#类可以派生自另一个类和任意多的接口

  • 实现继承:表示一个类型派生自一个基类型,它拥有该基类型的所有成员字段和函数,在需要给现有类型添加功能或者许多相关类型共享一组重要的公共功能时.这种类型继承非常有用
  • 接口继承:表示一个类型只继承了函数的签名,没有继承任何的实现代码

实现继承virtual/override

    /// <summary>
    /// 基类
    /// </summary>
    class Person
    {
        /// <summary>
        /// 使用virtual关键字定义的方法允许在派生类中使用override重写
        /// </summary>
        public virtual void SayHello()
        {
            Console.WriteLine("基类的SayHello");
        }
    }

    /// <summary>
    /// 派生自Person
    /// </summary>
    class ChinaPerson : Person
    {
        /// <summary>
        /// 使用override关键字重写基类的SayHello方法
        /// </summary>
        public override void SayHello()
        {
            Console.WriteLine("你好");
        }
    }

    /// <summary>
    /// 派生自Person
    /// </summary>
    class ThailandPerson : Person
    {
        public override void SayHello()
        {
            Console.WriteLine("萨瓦迪卡");
        }
    }

把一个基类函数声明为virtual,就可以在任何派生类中重写该函数,virtual也适用于属性;需要注意:成员字段和静态函数都不能声明为virtual,因为这个概念只对类中的实例成员有意义

隐藏方法

如果签名相同的方法在基类和派生类中都进行了声明,但该方法没有声明为virtual和override,派生类会隐藏基类方法

    class Person
    {
        public void SayHello()
        {
            Console.WriteLine("基类的SayHello");
        }
    }

    class ChinaPerson : Person
    {        //提示:隐藏继承的成员Person.SayHello,如果有意的,请使用关键字new
        public void SayHello()
        {
            Console.WriteLine("你好");
        }
    }

修改后

    class Person
    {
        public void SayHello()
        {
            Console.WriteLine("基类的SayHello");
        }
    }

    class ChinaPerson : Person
    {
        public new void SayHello()
        {
            Console.WriteLine("你好");
        }
    }

调用函数的基类版本

C#中可以使用base.<MethodName>()这种语法来调用方法的基类版本

 class Person
    {
        public virtual void SayHello()
        {
            Console.WriteLine("基类的SayHello");
        }
    }

    class ChinaPerson : Person
    {
        public override void SayHello()
        {
            base.SayHello();
            Console.WriteLine("你好");
        }
    }

抽象类和抽象函数

C#中允许把类或函数声明为abstract,抽象类不能被实例化.抽象函数也不能直接实现,必须在非抽象的派生类中重写

  • 如果类包含抽象函数,则该类也必须被声明为抽象的
  • 抽象方法只在派生类中真正实现,这表明抽象方法只存放函数原型,不涉及主体代码
  • 派生自抽象类的类需要实现其基类的抽象方法,才能实例化对象
  • 使用override关键子可在派生类中实现抽象方法,经override声明重写的方法称为重写基类方法,其签名必须与override方法的签名相同

密封类和密封方法

C#允许把类或方法声明为sealed,对于类而言,这表示不能继承该类,对于方法而言,这表示不能重写该方法

派生类的构造函数执行

  • 默认构造函数,如果没有为类指定任何构造函数,编译器会自动为类创建一个无参构造函数,用以初始化类的字段;如果为类编写了构造函数,那么编译器就不会再自动生成无参构造函数了。ps.C#不允许用户为结构定义无参构造函数。
  • 静态构造函数,不能访问实例成员,只能用来初始化一些静态字段或者属性,仅在第一次调用类的任何成员时自动执行,不带访问修饰符,不带任何参数,每个类只能有一个静态构造函数,但可以同时还有一个无参实例构造函数
  • 私有构造函数,将构造函数申明为私有的,则不能通过new运算符在外部代码中实例化(但可以编写一个静态方法或属性在其内部实例化一个对象,再将结果返回给外部代码)。私有构造函数的作用:永远不会被实例化,仅作为某些静态成员的容器/希望类智能通过某个静态方法来实例化(对象实例化的类工厂)
    class Program
    {
        static void Main(string[] args)
        {
            ChinaPerson chinaPerson = new ChinaPerson();
            Console.ReadKey();
        }
    }

    class Person
    {
        static Person()
        {
            Console.WriteLine("Person静态构造函数");
        }
        public Person()
        {
            Console.WriteLine("Person实例构造函数");
        }
    }

    class ChinaPerson : Person
    {
        static ChinaPerson()
        {
            Console.WriteLine("ChinaPerson静态构造函数");
        }

        public ChinaPerson()
        {
            Console.WriteLine("ChinaPerson实例构造函数");
        }
    }

输出

ChinaPerson静态构造函数

Person静态构造函数

Person实例构造函数

ChinaPerson实例构造函数

构造函数执行顺序为:调用System.Object.Object()->ChinaPerson被实例化所以调用自身的静态构造函数->跳到ChinaPerson的实例构造函数发现基类Person->Person类被调用,所以调用自身的Person静态构造函数->Person实例无参构造函数->:ChinaPerson实例无参构造函数(先调用System.Object的构造函数,再按照继承的层次结构从上往下进行,直到最终要实例化的类为止)

可以使用base关键字来实现不同构造函数的调用

接口继承

指定一组函数成员而不实现成员的引用类型,其它类型和接口可以继承接口

接口继承中又分为隐式实现和显式实现

    interface IPerson
    {
        void SayHello();
    }

    /// <summary>
    /// 隐式实现接口
    /// </summary>
    class ChinaPerson : IPerson
    {
        public void SayHello()
        {
            Console.WriteLine("你好");
        }
    }

    /// <summary>
    /// 显式实现接口
    /// </summary>
    class ThailandPerson : IPerson
    {
        void IPerson.SayHello()
        {
            Console.WriteLine("莎娃迪卡");
        }
    }

对于隐式实现的接口调用这两种方式都可以

            ChinaPerson chinaPerson = new ChinaPerson();
            IPerson person = new ChinaPerson();
            person.SayHello();
            chinaPerson.SayHello();

对于显式实现的接口调用:只能使用接口调用

            IPerson thailandPerson = new ThailandPerson();
            thailandPerson.SayHello();

抽象类和接口的区别

相同点:

  1. 都可以被继承
  2. 都不能被实例化
  3. 都包含方法声明
  4. 派生类必须实现未实现的方法

区别:

抽象基类可以定义字段/属性/方法实现.接口只能定义属性/索引器/事件/方法声明

抽象类是一个不完整的类,需要通过集成进一步细化.而接口更像是一个行为规范,表名我能做什么

接口是可以被多重实现的,可以有多个类实现接口,因为类的单一继承性,抽象类只能被单一继承

抽象类实现继承需要使用override关键字,接口则不用

如果抽象类实现接口,可以把接口方法映射到抽象类中作为抽象方法不必实现,而在抽象类的子类中实现接口方法

抽象类表示的是,这个对象时什么;接口表示都是,这个对象能做什么;使用抽象类是为了代码的复用,使用接口是为了实现多态性

普通类和抽象类的区别

相同点:

  • 都可以被继承
  • 抽象类不能实例化,普通类允许实例化
  • 抽象方法值包含方法声明而且必须包含在抽象类中
  • 子类继承抽象类必须实现抽象类中的抽象方法除非子类也是抽象类
  • 抽象类中可以包含抽象方法和实例方法

原文地址:https://www.cnblogs.com/GnailGnepGnaw/p/10603401.html

时间: 2024-10-10 06:56:45

第三章:继承/抽象类/接口的相关文章

Java入门 第二季第三章 继承

这是我学习慕课网Java课程的笔记,原视频链接为:http://www.imooc.com/learn/124 3-1 Java 中的继承  ★ 概念:继承是类与类的一种关系,是一种 "is a" 的关系                                  图:继承关系--狗 和 动物 注:Java 中的继承是单继承,即一个类只有一个父类  ★ 好处 ● 子类拥有父类的所有属性和方法,但如果有private修饰,则子类不能使用该属性或方法 ● 实现代码复用  ★ 语法规则

[Effective Java 读书笔记] 第三章类和接口 第二十-二十一条

第二十条 用函数对象表示策略 函数指针(JAVA的函数指针,是指使用对象的引用来作为参数,传递给另一个对象的方法)主要用来实现策略模式,为了在JAVA中实现这种模式,要申明一个接口来表示该策略,并为每个具体策略申明一个实现了该接口的类. 如果这个策略只被执行一次,使用匿名类,如果重复使用,则通常实现为私有的静态成员类,并通过共有的静态final域导出(最后一个例子),其类型为该策略接口. 第二十一条 优先考虑静态成员类 嵌套类主要有四种:静态成员类,非静态成员类,匿名类,局部类 静态成员类,一般

[Effective Java 读书笔记] 第三章类和接口 第十六条

第十六条 复合优先于继承 如果不确定B和A的关系是,is-a的关系,B确实也是A,那么久不应该使用B继承A,否则会暴露实现细节, 你的实现都会限制在原始的实现上. 书中举的第一个例子,实现了一个类extends HashSet类,因为缺少对HashSet类的addAll方法的理解(addAll会重复调用add方法),导致多统计了一倍的调用次数,这就是自己的实现限制在父类的实现上. 同时书中还有一个说明,如果超类在后续的版本中增加了一个新的方法, 正好和你的类里新增的方法签名一致(参数列表和函数名

[Effective Java 读书笔记] 第三章类和接口 第十二条

第十二条 使类和成员的可访问性最小化 总得来说,我们应该尽量将成员的访问范围限制到最小!有利于解耦,开发.测试和优化都能够更加独立. 对于成员(域,方法,嵌套类和嵌套接口),有四种可能的访问级别,访问范围从小到大: 1. private,只有声明成员的类的内部才能访问 2. 包级私有的,声明成员的类所在的包内的任何类都可以访问,如果成员不显示声明访问级别,就是这种级别,所以也成为缺省访问级别 3.protected,声明成员的类及其子类可以访问,并且声明类所在包中的任何类也可以访问 4.publ

[Effective Java 读书笔记] 第三章类和接口 第二十三-- ??条

第二十三条 请不要再新代码中使用原生态类型 1 使用原生态类型,就失去了泛型在安全性和表述性方面的所有优势,所以新代码中不要使用原生态类型 2 List<String>可以传递给List作为的参数,但是不能传递给List<Object>,因为泛型有子类型化的规则,List<String>是原生态类型List的一个子类型,而不是参数化类型List<Object>的子类型 3. 如果不确定类型,可以使用通配符类型 Set<?>,

基础学习day07---面向对象三---继承,接口与 抽象类

一.继承 1.1.继承概念 将对象的共性抽取出来.提取出一个单独的类. 继承使用复用以前的代码非常容易,能够大大的缩短开发周期,降低开发成本,同时增加程序的易维护性 继承使重一个类A能够直接使用另外一个类B的属性和方法的一种途径 类A可以有自己的属性和方法通过 extends 关键字让类与类之间产生继承关系. 让类和类之间产生了关系,有了这个关系,才有了多态的特性. 注意:千万不要为了获取其他类的功能,简化代码而继承. 必须是类与类之间有所属关系才可以继承,所属关系是 is  a.的关系 1.2

JAVA基础笔记(很实用)继承-多态-抽象类-接口-异常-集合-IO-线程-Socket

第七章:Java继承 一.继承的概念 1.一个父类派生出一个子类的机制称为继承. 2.承是重用程序代码的有力手段,当多个类之间存在相同的属性和方法时,可以从这些类中抽象出父类. 3.们只需要在父类中定义这些属性和方法,而子类无须重新定义这些属性和方法,直接从父类继承即可. 4.通过继承,子类就会自动的拥有在父类中定义的属性和方法. 5.两个或多个类的成员中存在一部分相同的情况,通过继承机制,可以利用现有的类来创建新的类. 6.子类不但拥有父类的成员,还可以定义新的成员. 7.可以提高软件的可重用

12.面向对象(继承/super/接口/抽象类)

面向对象继承与派生继承继承顺序继承原理子类调用父类的方法(super)组合接口接口的概念:接口的概念解释和使用:python中的接口:抽象类 面向对象 继承与派生 继承 什么是继承?继承是一种创建新的类的方式 class A: pass class B(A): pass 在python中,新建的类可以继承自一个或者多个父类,原始类称为基类或者超类,新建的类称为派生类或者子类 python中类的继承分为,单继承和多继承. 查看继承的方法B.__bases__ 如果没有指定基类,python的类会默

Java回顾:用一个Demo来说明继承抽象类和实现接口的简单框架模型

大家都知道,在java应用开发中,要"面向接口编程". 那么什么是接口?接口有什么作用?接口如何使用?我们一起来回顾一下. [声明]欢迎转载,但请保留文章原始出处:http://blog.csdn.net/yelangjueqi/article/details/44701369 1,接口回顾: 1.1,Java中接口的概念 在Java中接口是一种特殊的抽象类,跟一般的抽象类相比,接口里面的所有方法都是抽象方法,接口里面的所有属性都是常量.也就是说,接口里面只有方法定义而没有任何方法实现