企业🤖AI智能体构建引擎,智能编排和调试,一键部署,支持私有化部署方案 广告
### [忘掉对象类型](https://lingcoder.gitee.io/onjava8/#/book/09-Polymorphism?id=%e5%bf%98%e6%8e%89%e5%af%b9%e8%b1%a1%e7%b1%bb%e5%9e%8b) **Music.java**看起来似乎有点奇怪。为什么所有人都故意忘记掉对象类型呢?当向上转型时,就会发生这种情况,而且看起来如果`tune()`接受的参数是一个**Wind**引用会更为直观。这会带来一个重要问题:如果你那么做,就要为系统内**Instrument**的每种类型都编写一个新的`tune()`方法。假设按照这种推理,再增加**Stringed**和**Brass**这两种**Instrument**: ~~~ // polymorphism/music/Music2.java // Overloading instead of upcasting // {java polymorphism.music.Music2} package polymorphism.music; class Stringed extends Instrument { @Override public void play(Note n) { System.out.println("Stringed.play() " + n); } } class Brass extends Instrument { @Override public void play(Note n) { System.out.println("Brass.play() " + n); } } public class Music2 { public static void tune(Wind i) { i.play(Note.MIDDLE_C); } public static void tune(Stringed i) { i.play(Note.MIDDLE_C); } public static void tune(Brass i) { i.play(Note.MIDDLE_C); } public static void main(String[] args) { Wind flute = new Wind(); Stringed violin = new Stringed(); Brass frenchHorn = new Brass(); tune(flute); // No upcasting tune(violin); tune(frenchHorn); } } ~~~ 输出: ~~~ Wind.play() MIDDLE_C Stringed.play() MIDDLE_C Brass.play() MIDDLE_C ~~~ 这样行得通,但是有一个主要缺点:必须为添加的每个新**Instrument**类编写特定的方法。这意味着开始时就需要更多的编程,而且以后如果添加类似`tune()`的新方法或**Instrument**的新类型时,还有大量的工作要做。考虑到如果你忘记重载某个方法,编译器也不会提示你,这会造成类型的整个处理过程变得难以管理。 如果只写一个方法以基类作为参数,而不用管是哪个具体派生类,这样会变得更好吗?也就是说,如果忘掉派生类,编写的代码只与基类打交道,会不会更好呢? 这正是多态所允许的。但是大部分拥有面向过程编程背景的程序员会对多态的运作方式感到一些困惑。