JS++ |上倾和下倾
现在我们了解了子类型和静态与动态多态性,我们可以了解向上转换和向下转换。
向上转换和向下转换基于类型关系。换句话说,如果您有类型为“动物”的数据,则可以将其“向下转换”为它的子类型“狗”。相反,如果您有类型为“Dog”的数据,则可以将其“向上转换”到其超类型“Animal”。但是,您不能将任一类型的数据转换为“int”,因为“int”与“Animal”或“Dog”之间没有类型关系。
由于我们现在了解了编译时与运行时多态性,以及当数据类型指定为“Animal”时编译器为何以及如何解析“render”方法,让我们恢复我们的 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();
您会记得,这是渲染我们所有动物的代码,但我们不再在鼠标悬停时获得动物名称。解决这个问题的一种方法是沮丧:
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
修改后的 main.jspp 代码中有额外括号的原因是因为我们希望类型转换优先,以便在调用 'render' 方法之前进行转换。有关详细信息,请参阅 JS++运算符优先级表。
如果您现在编译并运行代码,您应该会看到当您将鼠标悬停在猫和狗的图标上时,它们会再次显示它们的名字。
为了说明向上转换,我们还可以将我们的一只猫转换为“动物”类型。在这只猫上调用 '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”升级为“动物”。如果您现在编译代码,您会注意到第一只猫(“Kitty”)的名字显示在鼠标悬停上,但第二只猫(“Kat”)没有相同的行为。
虽然我们能够使用强制转换解析正确的“渲染”方法,但这并不是解析该方法的最优雅的方式。例如,如果我们有一个“Animal”对象数组,我们的循环将嵌套在“if”语句中,执行“instanceof”检查和随后的类型转换。这并不理想,会导致代码难以阅读。还有一种更优雅的方式:虚方法。