关于 Java 多态 (Polymorphism)的一些 tips。
多态是同一个行为具有多个不同表现形式或形态的能力。
多态就是同一个接口,使用不同的实例而执行不同操作,如图所示:
对于多态,我们最熟悉的一种情况就是 引用类似被声明为父类后,可以把子类的实例赋值给这个引用。
Object any = new ArrayList<String>(); Object anyone = new String(); List<String> list = new LinkedList<>();
Object 是所有类型的父类,因此他声明的引用,可以执行任意他的子类对象,List 也是同理。
同时,我们也知道这个时候,这个引用在默认情况下也只能访问父类的属性和方法。比如这里的 any, 虽然想表达的是一个 ArrayList 对象,但是也只能访问 Object 的方法和属性。
当然,这里可以做强制类型转换。
这里只是举例,一般不会这么写代码的
关于多态,我们还知道,如果父类和子类声明了相同的方法,那么运行时,会执行子类中的方法。
现在,再来考虑下面这种情况。
这里使用截图,没用代码块主要是想体现一下 print 方法的调用情况,可以看到这里第一个 print 方法是高亮的
结果会是什么呢?
output
son invoked self ====== Son
可以看到,最终调用的是 Son 的 self 方法,但是执行的是第一个 print 方法,也就是参数类型为 Father 的方法。由此可见,方法匹配(暂时这么叫吧)是按声明类型执行的,但是在运行期,是按对象的实际类型执行的。
这里很容易在不经意间产生 bug。假设 print(Father param) 是后添加的,那么他在无形中屏蔽掉子类为参数的方法。如果这两个方法除了调用具体类型的方法,其他逻辑有差异的话,就非常危险了。
以上
因此,便有一下规律
Java的方法分派分为两种:
静态分派 - 方法重载分派
编译器就确定
依据调用者的声明类型和方法的参数类型匹配
动态分派 - 方法重写分派
运行时确定
依据调用者的实际类型分派