编译原理之美
宫文学
北京原点代码 CEO
46197 人已学习
新⼈⾸单¥59
登录后,你可以任选4讲全文学习
课程目录
已完结/共 45 讲
开篇词 (1讲)
编译原理 · 期中考试周 (1讲)
编译原理之美
15
15
1.0x
00:00/00:00
登录|注册

13 | 继承和多态:面向对象运行期的动态特性

利用多态特点的经验分享
框架和类库中的继承和多态应用
多态的应用
对象初始化过程
编译期和运行期的特性
子类型的现象
对象初始化过程中的特殊情况
super 的调用方式
this 的多种用法
逐级执行缺省的初始化方法
在继承关系下,对象初始化需要对所有祖先进行初始化
运行时类型信息(RTTI)
实现多态
根据运行时获得的类型信息进行动态绑定
编译期无法准确确定变量的真实类型
变量和函数的类型引用消解
设置作用域
识别新类型:Mammal、Cow、Sheep
运行期动态绑定方法
多态性的优势
子类可以重载父类的方法
同一方法在不同子类中执行不同动作
实现方式:名义子类型和结构化子类型
作用域覆盖
重用逻辑,避免重复实现
子类自动具备父类的属性和方法
一课一思
总结
this 和 super
对象的逐级初始化
运行期动态绑定方法
语义分析
多态
继承
面向对象编程的继承和多态

该思维导图由 AI 生成,仅供参考

面向对象是一个比较大的话题。在“09 | 面向对象:实现数据和方法的封装”中,我们了解了面向对象的封装特性,也探讨了对象成员的作用域和生存期特征等内容。本节课,我们再来了解一下面向对象的另外两个重要特征:继承和多态。
你也许会问,为什么没有在封装特性之后,马上讲继承和多态呢?那是因为继承和多态涉及的语义分析阶段的知识点比较多,特别是它对类型系统提出了新的概念和挑战,所以我们先掌握语义分析,再了解这部分内容,才是最好的选择。
继承和多态对类型系统提出的新概念,就是子类型。我们之前接触的类型往往是并列关系,你是整型,我是字符串型,都是平等的。而现在,一个类型可以是另一个类型的子类型,比如我是一只羊,又属于哺乳动物。这会导致我们在编译期无法准确计算出所有的类型,从而无法对方法和属性的调用做完全正确的消解(或者说绑定)。这部分工作要留到运行期去做,也因此,面向对象编程会具备非常好的优势,因为它会导致多态性。这个特性会让面向对象语言在处理某些类型的问题时,更加优雅。
而我们要想深刻理解面向对象的特征,就必须了解子类型的原理和运行期的机制。所以,接下来,我们从类型体系的角度理解继承和多态,然后看看在编译期需要做哪些语义分析,再考察继承和多态的运行期特征。
确认放弃笔记?
放弃后所记笔记将不保留。
新功能上线,你的历史笔记已初始化为私密笔记,是否一键批量公开?
批量公开的笔记不会为你同步至部落
公开
同步至部落
取消
完成
0/2000
荧光笔
直线
曲线
笔记
复制
AI
  • 深入了解
  • 翻译
    • 英语
    • 中文简体
    • 中文繁体
    • 法语
    • 德语
    • 日语
    • 韩语
    • 俄语
    • 西班牙语
    • 阿拉伯语
  • 解释
  • 总结

面向对象编程的继承和多态是面向对象语言的重要特性。继承使子类自动具备父类的属性和方法,实现了代码的重用,而多态则允许不同子类在调用相同方法时执行不同的动作,提供了灵活性和统一的使用方式。本文从类型体系的角度解释了继承和多态的概念,并介绍了子类型的概念,即子类型 is a 父类型,并探讨了子类型的实现方式。此外,文章还讨论了在编译期对继承和多态特性进行语义分析的挑战,以及在运行期实现方法的动态绑定的问题。通过本文,读者可以快速了解面向对象编程中继承和多态的重要性,以及相关的语义分析和动态绑定的技术特点。文章还介绍了在运行期实现方法的动态绑定的原理,以及继承情况下对象的实例化过程。最后,通过一个示例程序,深入讲解了this和super的语义和使用方法。整体而言,本文通过深入浅出的方式,帮助读者全面理解了面向对象编程中继承和多态的重要概念,以及相关的技术特点。

仅可试看部分内容,如需阅读全部内容,请付费购买文章所属专栏
《编译原理之美》
新⼈⾸单¥59
立即购买
登录 后留言

全部留言(17)

  • 最新
  • 精选
  • 曾经瘦过
    看到了评论 泛型 然后想到了反射。根据使用经验(反射报错都是在运行时),老师在后端的部分会讲一下反射吗?

    作者回复: 我看看在讲Java那讲里能否把这个内容兼顾。 有同学提的泛型,其实我还没有安排进去...实在不行做个加餐。 这里先提一句:java的泛型其实只是语法糖,是在基础语法的基础上封装了一层而已。运行期,带泛型和不带泛型的,是完全同一套代码,没区别。LinkedList<String>和LinkedList<Object>运行时没区别。只是在编译期添加了额外的类型检查功能。 这跟C++的模板完全不是一回事。

    2019-09-27
    2
    13
  • Gopher
    老师能增加一讲泛型吗?这样就圆满了🤣

    作者回复: 好的,我把这个问题在答疑那讲里作为一个点。

    2019-09-15
    7
  • 影影影
    老师您好,有些小的疑惑,麻烦解答下。 对于文中提到的,在ThisSuperTest.java类中调用Mammal的构造方法Mammal(int weight)后调用this.speak()这个例子。 根据您的解释,是会调用Cow类的speak函数。其中您也提到了,在调用这个方法时,Cow类初始化并没有开始。 因此我的疑惑是,在一个类(Cow)的实例没有初始化的时候,为何就已经可以去调用这个实例的方法了?

    作者回复: Java语言的成员变量,只要给它分配了内存空间,就一定会做初始化。所以,即使还没有运行这个类的构造方法,其实这些变量也都可以用了,只不过里面的是缺省值。 Java只所以采取这个机制,可能就是跟面向对象的生存期特征有关的。也就是,所有成员变量要在调用任何方法之前就创建,并且可用。所以,这个时候调用方法并没有问题。 所以,Cow类的初始化过程,如果用放大镜看的话,可能会分成多个阶段。对于int a = 10;这样一个语句来说: 阶段1:Cow及其父类的成员属性都获得了内存,并具备了缺省值。 阶段2:使用变量声明时的初始化部分,让a的值变为10; 在这个阶段,其实还可以用int a = b;或者int a = foo()这样的方式来做初始化,这时候要求b一定是在a的前面。 阶段3:运行自定义的构造函数。这时候,a的值可能又被修改成其他值。

    2019-09-13
    4
    4
  • xiaobang
    Java里面构造函数里面居然允许多态,感觉行为怪怪的,不符合自觉。另外ThisSuperTest里面那个weihgt和speak 前面不加this 语义也一样吗

    作者回复: 允许多态正常,因为虽然是在构造函数中,但已经要使用对象的方法了,所以多态逻辑就会发生作用。 不过,java对象的初始化的语法设计,似乎还可以做得更好。比如,如果调用super(),必须出现在第一行等等。需要明白初始化的原理,才会理解为什么这么设计。 另,你的问题:加不加this都是一样的。

    2019-09-17
    2
    3
  • 林恒杰
    现在深度学习的端侧芯片碎片化比较严重,因而对于编译器需求也开始变多起来,包括谷歌最近也像LLVM社区提交了MLIR,老师可以讲一下这个部分的看法吗?

    作者回复: 好的,我安排在后端部分会讨论一下这个问题。 深度学习发展速度太快。从长远来看,需要标准的IR。这又是一次标准之争。

    2019-09-11
    3
  • 李懂
    也就是只有方法存在多态,属性和构造函数是不存在多态! 这个this,super是咋实现的,以前觉得this是当前对象 super是父类对象,现在看来好像不对!

    作者回复: 总的来说,this和super在三个场景中,它的语义是有差别的。 场景1:对象属性:适用原理,是变量作用域。 场景2:对象方法:适用原理,是多态; 场景3:构造方法。这个只是长得像方法,其实不是方法。要用对象初始化的逻辑去分析它。 this和super的实现,你可以参考一下playscript-java的代码。 另外,可以再像ThisSuperTest.java一样,写点代码深入测试一下this和super特性。

    2019-09-11
    2
    3
  • 余晓飞
    // 在本级查找这个这个方法 Function rtn = super.getFunction(name, paramTypes); 这里需要首先在本级查找,但是根据下文介绍的super特性,这里查找的应该是上级及以上的方法,是在这里和Java有差别吗?

    作者回复: 抱歉回复晚了。 方法的overide,是下级覆盖商机,所以应该先从下级查找。如果下级实现了,就用下级的。 如果下级没有,就用上级的,这就是inheritence。

    2019-09-22
    2
    2
  • cry soul
    还有一个点,其实比较想知道的是多线程的实现。以及线程安全问题等,怎么样实现是原子级的操作。希望老师能稍微提及这样的内容,因为本身是做web开发的,真的比较好奇。

    作者回复: 线程的原理,是操作系统的内容,你可能要去那门课程多学一下:) 过去的语言(如C语言),只是提供标准的库,让你访问操作系统的线程管理功能,包括信号量、同步互斥什么的。 Java语言增加了一些专门处理多线程的元素,比如synchronized关键字。 go语言又更进一步,把操作系统的线程进行了封装,变成了轻量级的goroutine,很受欢迎。

    2019-10-11
    3
    1
  • 沉淀的梦想
    看代码的时候有个疑问,this作为一个primary,当要去找其左值的时候,会去各个作用域中搜索thisRef,但是thisRef是什么时候加入到作用域的符号表的呢?没有找到代码中对应的位置

    作者回复: 在RefResolver.exitPrimary()中,在这里做与primary有关的引用消解。 This variable = theClass.getThis(); at.symbolOfNode.put(ctx, variable);

    2019-09-13
    1
  • 沉淀的梦想
    看老师的代码里好像没有对类方法和对象方法进行区分,是因为PlayScript目前还不支持类方法吗?

    作者回复: 对,目前没有支持类方法。也没有支持类级别的成员变量。

    2019-09-13
    1
收起评论
显示
设置
留言
17
收藏
沉浸
阅读
分享
手机端
快捷键
回顶部