什么是多态?
概念:
因编译期间状态和运行期间状态不一致,父类型的引用可以指向子类型的对象,让程序产生了多种形态的概念。对于多态还有以下相关知识点:
(1) 向上转型:也就是由子类型向父类型转换,也可以理解成自动类型转换,名称为upcasting
(2) 向下转型:也就是由父类型向子类型转换,也可以理解成为强制类型转换,需要加强制类型转换运算符。
上述两种类型转换必须要有父子继承关系,才能完成向上转型或者向下转型,如果无继承关系,则在编译期间就不会通过。
语法机制:
java程序分为编译阶段和运行阶段,比较形象的理解的话,编译是在检查语法,而运行则是jvm底层工作。关于编译阶段和运行阶段,以下有几个要点需要注意:
-
一个完整的java程序在整个执行过程,一定是先进行分析编译、语法检查,然后实际运行。编译若都不通过,则实际运行不起来。
-
编译阶段,编译器会去检查父类引用的数据类型为父类,并且在父类的.class文件中有与即将要调用同名方法所以编译可以通过。这个阶段我们叫做静态绑定或者叫编译阶段绑定。
PS:编译阶段不能创建对象,只能检查语法。
-
在程序运行阶段,jvm堆内存当中真实创建的对象实际是子类的对象,那么在运行的时候,一定会调用子类对象中的同名放方法,此时发生了程序的动态绑定,也叫运行阶段绑定
PS:程序运行过程中,只和底层对象有关,底层是什么对象,就调用对象中的方法
针对上述三个要点,我们需要引出一个例子来进行
class A{
public void 方法1(){
}
}
class B extends A{
public void 方法1(){
}
public void 方法2(){
}
}
public class Test{
A a = new B();
// -------------------------
a.方法2();
/*
这个时候会报语法错误,或者也就是叫编译错误
*/
}
为什么会报错了?
从创建对象那段代码来看,我们是创建了一个B对象并将实际对象的内存地址赋给了A类型的变量a,也就是父类型的引用。所以在"a.方法2()"的时候,编译器会去寻找变量a所属的数据类型去找到这个类中是否有a.方法2()这个方法,很显然是没有找到的,从而导致静态绑定失败了。