前言
李刚老师《JAVA疯狂讲义》第5版,第5章学习笔记。
JAVA中的多态
JAVA中的多态指的是,相同的变量,调用相同的方法,结果却不一样。具体如下:
//定义一个Person类
public class Person{
//Person类的成员变量
int age = 10;
//Person类的方法
public void eat() {
System.out.println("我是人的吃饭方法");
}
}
//定义一个Person类的子类,Police类
public class Police extends Person{
//Police类的成员变量
int age = 20;
//Police类的方法
public void eat() {
System.out.println("我是警察的吃饭方法");
}
public void goOut() {
System.out.println("我是警察的巡逻方法");
}
}
//定义一个Person类的子类,Doctor类
public class Doctor extends Person{
int age = 30;
public void eat() {
System.out.println("我是医生的吃饭方法");
}
public void work() {
System.out.println("我是医生的工作方法");
}
}
上述代码中,定义了三个类:Person、Police、Doctor,其中,Person是Police和Doctor类的父类。三个类中均定义了一个成员变量age,但取值不同。三个类中均定义了一个方法eat(),但输出不同。Police类还有一个独有的方法goOut(),Doctor类还有一个独有的方法work()。
接下来,运行以下代码:
public class Demo01 {
public static void main(String[] args) {
Person A = new Police();
//输出:我是警察的吃饭方法
A.eat();
Pearson B = new Doctor();
//输出:我是医生的吃饭方法
B.eat();
}
}
可以见到,同样的两个Person类的引用变量A、B,调用同样的eat()方法,得到的结果不同,这就是多态。
那么为什么会这样呢?
在JAVA中,引用变量存在两种类型,一种是编译时的类型,一种是运行时的类型,例如:
Person A = new Police();
引用变量A在编译时的类型为Person,在运行时的类型为Police。因为子类是一种特殊的父类,因此JAVA允许把一个子类对象赋值给一个父类引用变量。这种类型转换由系统自动完成。
当运行时调用该引用变量的方法时,其方法行为总是表现出子类的特征,而并非父类的特征。因此出现了上述结果。
但是,A并不能调用Police()所独有的方法,例如:
public class Demo01 {
public static void main(String[] args) {
Person A = new Police();
//下面语句将会报错
A.goOut();
}
}
这段代码将会报错:
Exception in thread “main” java.lang.Error: Unresolved compilation problem:
The method goOut() is undefined for the type Person
就是说Person类里面,没有定义goOut()这个方法。
同时,成员变量也不会呈现出多态的特性,例如:
public class Demo01 {
public static void main(String[] args) {
Person A = new Police();
//输出:10
System.out.println(A.age);
Person B = new Doctor();
//输出:10
System.out.println(B.age);
}
}
两个都会输出10,而不会一个输出20,一个输出30。
同时,静态方法不会呈现出多态的特性,因为静态方法不能被重写,例如:
public class Person {
int age = 10;
public static void eat() {
System.out.println("我是人的吃饭方法");
}
}
public class Police extends Person {
int age = 20;
public static void eat() {
System.out.println("我是警察的吃饭方法");
}
public void goOut() {
System.out.println("我是警察的巡逻方法");
}
}
public class Demo01 {
public static void main(String[] args) {
Person A = new Police();
//输出:我是人的吃饭方法
A.eat();
}
}
可以看到,由于eat()是静态方法,因此并没有呈现出多态的特性。
综上,对于JAVA中的多态总结如下:
- 父类中的非静态方法被子类重写后,可以呈现出多态的特征
- 父类中的静态方法不能被重写,不会呈现出多态的特征
- 父类中的成员变量也不会呈现出多态的特征
- 引用类型能够调用的方法取决于其编译类型,引用类型调用方法的具体结果取决于其运行类型。
对于第4条,例如:
Person A = new Police();
A在编译时的类型为Person ,因此只能调用Person 类中包含的方法,而不能调用Police()这个子类所特有的goOut()方法。A在运行时的类型为Police,因此执行eat()这个方法时,是按照Police这个类中定义的方法去执行的。(其实对于这一块笔者也有些疑问,因为笔者不清楚JAVA运行的底层机制,所以不清楚为什么会出现这种情况,如果有大佬知道的话,希望能告诉俺一下!)