📜  JS++ |静态与动态多态性

📅  最后修改于: 2022-05-13 01:55:04.080000             🧑  作者: Mango

JS++ |静态与动态多态性

静态多态是在编译时发生的多态,动态多态是在运行时(应用程序执行期间)发生的多态。

静态多态性的一个方面是早期绑定。在早期绑定中,要调用的特定方法在编译时解析。 (JS++ 还支持通过虚函数进行后期绑定,我们将在后面介绍。)早期绑定更快,因为没有运行时开销。早期绑定是默认行为,也是 JS++ 最常见的行为。如果你想要后期绑定,你必须明确指定它。同样,我们将在后面的部分中介绍后期绑定。

在我们的代码中,我们为“Cat”和“Dog”类的 render() 方法指定了“overwrite”修饰符。这启用了方法隐藏,但它指定了早期绑定。这是来自 Cat.jspp 的代码:

overwrite void render() {
    $element.attr("title", _name);
    super.render();
}

后来,当我们在 main.jspp 中将猫的类型更改为“动物”时,我们的猫的类型从“猫”更改为“动物”。你可能会说,“是的,但是我们仍然使用 'Cat' 类来实例化我们的猫对象。”虽然这是真的,但这也意味着我们的 cat 变量现在可以接受满足“Animal”约束的任何类型的数据(如果我们没有在“Animal”上指定受保护的构造函数,则包括“Animal”本身)。例如,这现在变成了完全可以接受的代码:

import System;
import Animals;

Animal cat1 = new Cat("Kitty");
if (Math.random(1, 10) > 3) {
    cat1 = new Dog("Fido");
}
cat1.render();

忽略“系统”导入,但它会导入 Math.random()函数。它用于说明示例。我还特意将变量的名称保留为“cat1”来说明这一点。 “cat1”的类型为“动物”。因此,“Animal”类型的所有对象都可以分配给“cat1”(包括“Dog”类型的对象)。

如果您实际编译、运行上面的代码并充分刷新,您会注意到您的“猫”有时会呈现为狗。

正如你所看到的,当我们有一个“动物”类型时,我们程序中的数据可以是“猫”,也可以根据运行时随机数生成随机变成“狗”。随机数不是在编译时生成的。随机数是在应用程序执行(运行时)期间生成的。因此,从编译器的角度来看,如果我们要解析 'render' 方法,我们将把它解析为用户指定类型 'Animal' 的 'render' 方法,因为它是最正确的。回想一下,在子类型中,所有的猫和狗都是动物,但并非所有的动物都是猫和狗。

因此,这有望帮助您理解早期绑定和静态/编译时多态性。

旁白:作为规范的数据类型

数据类型也是规范。我们正在指定什么是正确的程序。例如,您不会指定一个“减法”函数来接受两个“字符串”类型的参数。在我们的例子中,如果我们想要一只猫,我们应该指定类型“Cat”而不是概括为“Animal”。虽然用更一般的术语表达算法的能力是可取的,但它可能并不总是正确的。

从技术上讲,该程序仍然是类型正确的。在这两种情况下(“猫”和“狗”),我们都有一个“动物”类型的对象。碰巧我们的“Animal”被命名为“cat1”,因此上述代码的一个潜在修复可能是将变量重命名为“animal”或类似的东西来表达我们的意图。

如果我们希望“cat1”始终是一只猫,另一个可能的解决方法是将数据类型限制为“猫”而不是“动物”。如果你这样做,你会得到一个编译错误,因为 'Dog' 不是 'Cat' 的子类型:

JSPPE5000: Cannot convert `Animals.Dog' to `Animals.Cat' at line 6 char 8 at main.jspp

在运行时多态中,类型是在运行时确定的。例如,我们可以使用“instanceof”运算符来检查运行时数据类型。更改您的 main.jspp 文件并观察结果:

import System;
import Animals;

external $;

Animal animal = new Cat("Kitty");
if (Math.random(1, 10) > 3) {
    animal = new Dog("Fido");
}

if (animal instanceof Cat) {
    $("#content").text("We have a CAT.");
}
else {
    $("#content").text("We have a DOG.");
}

保持刷新,您应该会看到有时我们有一个“Cat”实例,有时我们有一个“Dog”实例。但是,类型(和结果消息)是在运行时确定的,而不是编译时。