JS++ 子类型多态性

JS++ 子类型多态性

子类型描述了类型关系,子类型多态性使得为超类型定义的操作可以安全地被子类型替代。具体来说,想象一下 “猫 “类和 “动物 “类之间的关系。(记住:类在JS++中创建数据类型。)在这种情况下,在类型关系的背景下,’猫’是’动物’的子类型,’动物’是’猫’的超类型。用更简单的话来说,’猫'”是’动物’,但’动物’不是’猫’。理论上,这意味着所有适用于’Animal’数据类型的操作都应该接受对’Cat’类型的数据进行操作;但是,反过来就不对了:为’Cat’数据类型定义的操作将不能安全地对’Animal’类型的数据进行操作。

如果你还记得上一节的代码,猫和狗是有名字的驯养动物。然而,并不是所有的动物都应该被命名,所以我们的’动物’类并没有接受一个名字参数。因此,虽然我们可以在’猫’的实例上定义并调用一个’名字’获取器,但我们不能安全地用’动物’实例来替代’猫’实例。在JS++中,如果你试图这样做,你会得到一个错误。

子类型多态性允许我们以更抽象的方式编写代码。例如,在原始类型的范围内,’字节’代表0到255范围内的数字。同时,”int “代表更大范围内的数字:-2, 147, 483, 648到2, 147, 483, 647。因此,我们可以用 “字节 “类型的数字代替 “int “类型的数字。

int add(int a, int b) {
    return a + b;
}

byte a = 1;
byte b = 1;
add(a, b);

因此,我们能够更 “普遍 “地表达算法和函数,因为我们可以为任何给定的算法或函数接受更多种类的数据(按数据类型分类)。

重要的是,不要把子类型和继承混为一谈,尽管这两个概念在面向对象编程中是密切相关的。子类型描述的是类型关系,而继承关注的是实现(如用派生类扩展基类的实现)。子类型化可以适用于接口,而 “继承 “则不能。在后面的章节中,当我们讨论接口时,这个概念会变得更加清晰。

作为实际理解子类型的一个起点,我们可以改变main.jspp,使我们所有变量的数据类型变成 “动物”,但我们保留类的实例化作为子类型。

import Animals;

Animal cat1 = new Cat("Kitty");
cat1.render();
Animal cat2 = new Cat("Kat");
cat2.render();
Animal dog = new Dog("Fido");
dog.render();
Animal panda = new Panda();
panda.render();
Animal rhino = new Rhino();
rhino.render();

编译你的代码。它应该能成功编译,因为在实例化过程中,所有属于 “动物 “子类型的数据都可以分配给 “动物 “类型的变量。在这种情况下,”猫”、”狗”、”熊猫 “和 “犀牛 “的数据都可以被安全地分配给 “动物 “变量。

然而,有一个小的 “疑点”。打开index.html。你会看到所有的动物再次被呈现出来,但是,如果你把鼠标悬停在任何一个动物图标上,你就不会看到任何名字!这就是为什么会出现这种情况。要理解为什么会出现这种情况,我们必须理解静态与动态多态性,这将在下一节解释。(简而言之,我们实际上是通过在’render’方法上使用’overwrite’关键字来指定我们想要 “静态 “或编译时多态性。因此,我们得到了指定的行为)。

Python教程

Java教程

Web教程

数据库教程

图形图像教程

大数据教程

开发工具教程

计算机教程

JavaScript 教程