编译原理之美
宫文学
北京物演科技CEO
立即订阅
8171 人已学习
课程目录
已完结 43 讲
0/4登录后,你可以任选4讲全文学习。
开篇词 (1讲)
开篇词 | 为什么你要学习编译原理?
免费
实现一门脚本语言 · 原理篇 (13讲)
01 | 理解代码:编译器的前端技术
02 | 正则文法和有限自动机:纯手工打造词法分析器
03 | 语法分析(一):纯手工打造公式计算器
04 | 语法分析(二):解决二元表达式中的难点
05 | 语法分析(三):实现一门简单的脚本语言
06 | 编译器前端工具(一):用Antlr生成词法、语法分析器
07 | 编译器前端工具(二):用Antlr重构脚本语言
08 | 作用域和生存期:实现块作用域和函数
09 | 面向对象:实现数据和方法的封装
10 | 闭包: 理解了原理,它就不反直觉了
11 | 语义分析(上):如何建立一个完善的类型系统?
12 | 语义分析(下):如何做上下文相关情况的处理?
13 | 继承和多态:面向对象运行期的动态特性
实现一门脚本语言 · 应用篇 (2讲)
14 | 前端技术应用(一):如何透明地支持数据库分库分表?
15 | 前端技术应用(二):如何设计一个报表工具?
实现一门脚本语言 · 算法篇 (3讲)
16 | NFA和DFA:如何自己实现一个正则表达式工具?
17 | First和Follow集合:用LL算法推演一个实例
18 | 移进和规约:用LR算法推演一个实例
实现一门脚本语言 · 热点答疑与用户故事 (2讲)
19 | 案例总结与热点问题答疑:对于左递归的语法,为什么我的推导不是左递归的?
用户故事 | 因为热爱,所以坚持
编译原理 · 期中考试周 (1讲)
期中考试 | 来赴一场100分的约定吧!
免费
实现一门编译型语言 · 原理篇 (12讲)
20 | 高效运行:编译器的后端技术
21 | 运行时机制:突破现象看本质,透过语法看运行时
22 | 生成汇编代码(一):汇编语言其实不难学
加餐 | 汇编代码编程与栈帧管理
23 | 生成汇编代码(二):把脚本编译成可执行文件
24 | 中间代码:兼容不同的语言和硬件
25 | 后端技术的重用:LLVM不仅仅让你高效
26 | 生成IR:实现静态编译的语言
27 | 代码优化:为什么你的代码比他的更高效?
28 | 数据流分析:你写的程序,它更懂
29 | 目标代码的生成和优化(一):如何适应各种硬件架构?
30 | 目标代码的生成和优化(二):如何适应各种硬件架构?
实现一门编译型语言 · 应用篇 (2讲)
31 | 内存计算:对海量数据做计算,到底可以有多快?
32 | 字节码生成:为什么Spring技术很强大?
实现一门编译型语言 · 扩展篇 (3讲)
33 | 垃圾收集:能否不停下整个世界?
34 | 运行时优化:即时编译的原理和作用
35 | 案例总结与热点问题答疑:后端部分真的比前端部分难吗?
面向未来的编程语言 (3讲)
36 | 当前技术的发展趋势以及其对编译技术的影响
37 | 云编程:云计算会如何改变编程模式?
38 | 元编程:一边写程序,一边写语言
结束语 (1讲)
结束语 | 用程序语言,推动这个世界的演化
编译原理之美
登录|注册

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

宫文学 2019-09-11
面向对象是一个比较大的话题。在“09 | 面向对象:实现数据和方法的封装”中,我们了解了面向对象的封装特性,也探讨了对象成员的作用域和生存期特征等内容。本节课,我们再来了解一下面向对象的另外两个重要特征:继承和多态。
你也许会问,为什么没有在封装特性之后,马上讲继承和多态呢?那是因为继承和多态涉及的语义分析阶段的知识点比较多,特别是它对类型系统提出了新的概念和挑战,所以我们先掌握语义分析,再了解这部分内容,才是最好的选择。
继承和多态对类型系统提出的新概念,就是子类型。我们之前接触的类型往往是并列关系,你是整型,我是字符串型,都是平等的。而现在,一个类型可以是另一个类型的子类型,比如我是一只羊,又属于哺乳动物。这会导致我们在编译期无法准确计算出所有的类型,从而无法对方法和属性的调用做完全正确的消解(或者说绑定)。这部分工作要留到运行期去做,也因此,面向对象编程会具备非常好的优势,因为它会导致多态性。这个特性会让面向对象语言在处理某些类型的问题时,更加优雅。
而我们要想深刻理解面向对象的特征,就必须了解子类型的原理和运行期的机制。所以,接下来,我们从类型体系的角度理解继承和多态,然后看看在编译期需要做哪些语义分析,再考察继承和多态的运行期特征。
取消
完成
0/1000字
划线
笔记
复制
© 版权归极客邦科技所有,未经许可不得传播售卖。 页面已增加防盗追踪,如有侵权极客邦将依法追究其法律责任。
该试读文章来自付费专栏《编译原理之美》,如需阅读全部文章,
请订阅文章所属专栏。
立即订阅
登录 后留言

精选留言(11)

  • Gopher
    老师能增加一讲泛型吗?这样就圆满了🤣

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

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

    作者回复: 线程的原理,是操作系统的内容,你可能要去那门课程多学一下:)

    过去的语言(如C语言),只是提供标准的库,让你访问操作系统的线程管理功能,包括信号量、同步互斥什么的。

    Java语言增加了一些专门处理多线程的元素,比如synchronized关键字。

    go语言又更进一步,把操作系统的线程进行了封装,变成了轻量级的goroutine,很受欢迎。

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

    作者回复: 我看看在讲Java那讲里能否把这个内容兼顾。

    有同学提的泛型,其实我还没有安排进去...实在不行做个加餐。

    这里先提一句:java的泛型其实只是语法糖,是在基础语法的基础上封装了一层而已。运行期,带泛型和不带泛型的,是完全同一套代码,没区别。LinkedList<String>和LinkedList<Object>运行时没区别。只是在编译期添加了额外的类型检查功能。
    这跟C++的模板完全不是一回事。

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

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

    2019-09-22
  • Giacomo
    老师,现在流行的计算机语言中,有没有结构化继承的啊?因为我自己想写的语言本身是结构化继承的

    作者回复: 能把你的“结构化继承”的含义描述得更细致一些吗?
    如果你是指基于结构体来做继承,go语言做得就不错。你可以了解一下。对组合的支持做得很好。

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

    作者回复: 允许多态正常,因为虽然是在构造函数中,但已经要使用对象的方法了,所以多态逻辑就会发生作用。

    不过,java对象的初始化的语法设计,似乎还可以做得更好。比如,如果调用super(),必须出现在第一行等等。需要明白初始化的原理,才会理解为什么这么设计。

    另,你的问题:加不加this都是一样的。

    2019-09-17
  • 影影影
    老师您好,有些小的疑惑,麻烦解答下。
    对于文中提到的,在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
    1
  • 沉淀的梦想
    看代码的时候有个疑问,this作为一个primary,当要去找其左值的时候,会去各个作用域中搜索thisRef,但是thisRef是什么时候加入到作用域的符号表的呢?没有找到代码中对应的位置

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

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

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

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

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

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

    作者回复: 总的来说,this和super在三个场景中,它的语义是有差别的。
    场景1:对象属性:适用原理,是变量作用域。
    场景2:对象方法:适用原理,是多态;
    场景3:构造方法。这个只是长得像方法,其实不是方法。要用对象初始化的逻辑去分析它。

    this和super的实现,你可以参考一下playscript-java的代码。
    另外,可以再像ThisSuperTest.java一样,写点代码深入测试一下this和super特性。

    2019-09-11
    1
收起评论
11
返回
顶部