多态是面向对象中的一个很重要的部分,这里将介绍下在Java中多态访问方法的原理。
一、先简单介绍下多态:同一个方法在不同的类中,执行不同的方法,有不同的结果。
简单来讲就是:子类重写父类的方法,然后当子类对象赋给父类变量时执行该方法会执行子类方法。
二、原理:
这里需要引出一个方法表的概念:对于每一个类都会有一个方法表。
如下代码:
class Demo1{
public void demo1(){
}
public void demo2(){
}
}
class Demo2 extends Demo1{
public void demo2(){
}
public void demo3(){
}
}
Demo1类的方法表为:
Demo1:
demo1() -> Demo1.demo1()
demo2() -> Demo1.demo2()
Demo2类的方法表为:
Demo2:
demo1() -> Demo1.demo1()
demo2() -> Demo2.demo2()
demo3() -> Demo2.demo3()
这里引申一下:Java中方法的调用是先查看这个类的方法表看能否找到这个方法和对应的参数,然后执行,没有就报错。
由方法表可知:
- 子类继承的父类的方法,作用的范围是父类
- 子类重写父类的方法(重写要求,变量类型和方法名相同),作为范围为子类,无法调用父类的隐藏变量。所以子类重写后若想访问父类的域,需要调用super.父类域访问器。
- 子类重写方法后,方法在方法表中位置不变,只是有父类变成子类
注意: 如果将子类对象赋给父类变量时,该变量只能访问父类的方法(可多态),但不能执行子类特有的方法。
原理:在Java中变量的类型不仅规定了读取内存的方式,还规定了大小。拿C++距离,int* 类型要读取四个字节,但没有规定要读多少。
在多态时,父类变量读取子类方法表的大小只有父类方法表那么大,例如:
Demo1 demo = new Demo2;
那么demo可以读取的方法表为
Demo2:
demo1() -> Demo1.demo1()
demo2() -> Demo2.demo2()
另注:在Java中,隐藏方法不会继承,域或者说变量和静态方法都无法多态。原因:域的访问是通过编译器解析,而不是查看方法表,而静态方法是与类捆绑的。