既然我们了解了子类型和静态与动态多态性,我们就可以了解向上投射和向下投射。
向上投射和向下投射基于类型关系。换句话说,如果你有’Animal’类型的数据,你可以把它“下推”到它的子类型’Dog’。相反,如果你有“Dog”类型的数据,你可以“向上”它的超类型“Animal”。但是,不能将这两种类型的数据强制转换为“int”,因为“int”和“Animal”或“Dog”之间没有类型关系。
由于我们现在已经了解了编译时多态性与运行时多态性,以及当数据类型被指定为“动物”时编译器解析“render”方法的原因和方式,让我们恢复我们的主要功能。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();
正如你们所记得的,这是呈现我们所有动物的代码,但我们不再在鼠标上看到动物的名字。解决这一问题的一种方法是沮丧:
import Animals; Animal cat1 = new Cat("Kitty"); ((Cat) cat1).render(); Animal cat2 = new Cat("Kat"); ((Cat) cat2).render(); Animal dog = new Dog("Fido"); ((Dog) dog).render(); Animal panda = new Panda(); panda.render(); Animal rhino = new Rhino(); rhino.render();
类型转换的语法为:
(type) expression
例如:
(int) 100
我们修改后的主要内容中有额外括号的原因。jspp代码是因为我们希望类型强制转换优先,以便发生强制转换 之前 调用“render”方法。看到了吗 JS++运算符优先表 更多细节。
如果您现在编译并运行代码,您应该会看到,当您将鼠标悬停在猫和狗的图标上时,它们会再次显示自己的名字。
为了说明向上投射,我们还可以将一只猫投射到“动物”类型。在此cat上调用“render”方法意味着它使用的是“Animal”类render()方法,该方法不包括以下名称:
import Animals; Animal cat1 = new Cat("Kitty"); ((Cat) cat1).render(); Cat cat2 = new Cat("Kat"); ((Animal) cat2).render(); Animal dog = new Dog("Fido"); ((Dog) dog).render(); Animal panda = new Panda(); panda.render(); Animal rhino = new Rhino(); rhino.render();
请注意,我将“cat2”的类型改回了“Cat”,以演示向上转换。从那里,我将“cat2”向上投射到“Animal”。如果现在编译代码,您会注意到第一只猫(“Kitty”)的名字显示在鼠标上方,但第二只猫(“Kat”)没有相同的行为。
虽然我们能够使用强制转换解决正确的“渲染”方法,但这并不是解决该方法的最优雅的方法。例如,如果我们有一个“Animal”对象数组,我们的循环将嵌套在执行“instanceof”检查和后续类型转换的“if”语句中。这并不理想,会导致代码难以阅读。还有一种更优雅的方法:虚拟方法。