预备知识
面向对象编程--------理解多态
面向对象编程-------多态
向上转型
示例一
目录结构
原理&实现代码
老师专用门禁卡和学生专用门禁卡都继承了门禁卡。
AccessCard(父类:门禁卡)
package learn_extends.e1;
public class AccessCard {
public void entrance() {
System.out.println("验证身份,进出大门");
}
}
StudentAccessCard(子类:学生专用门禁卡)
package learn_extends.e1;
public class StudentAccessCard extends AccessCard {
@Override
public void entrance() {
super.entrance();
System.out.println("同学们注意安全");
}
}
TeacherAccessCard(子类:老师专用门禁卡)
package learn_extends.e1;
public class TeacherAccessCard extends AccessCard {
@Override
public void entrance() {
super.entrance();
System.out.println("欢迎 XXX 老师");
}
}
Main
package learn_extends.e1;
public class Main {
public static AccessCard[] createCardArray() {
AccessCard[] array = new AccessCard[10];
for (int i = 0; i < 5; i++) {
AccessCard o = new StudentAccessCard(); // 向上转型
array[i] = o;
}
for (int i = 5; i < 10; i++) {
AccessCard o = new TeacherAccessCard(); // 向上转型
array[i] = o;
}
return array;
}
// 相同的东西,表现不同的形态 —— 多态
public static void main(String[] args) {
AccessCard[] array = createCardArray();
for (AccessCard o : array) {
// 目前 o 指向的对象,可能是老师专用的 OR 学生专用的
o.entrance(); // 跟着对象类型走
// 前 5 个是学生,后 5 个是老师
System.out.println("=========================");
}
}
}
AccessCard o = new StudentAccessCard();
AccessCard o = new TeacherAccessCard();
在这里发生了向上转型,引用都是父类的引用,对象不同,执行entrance()
方法是,根据子类重写了父类的该方法,最后执行的结果就不同了。
运行结果
示例二
目录结构
原理分析&代码实现
Person
package learn_extends.e2;
public class Person {
public String getName() {
return "person";
}
}
Teacher
package learn_extends.e2;
public class Teacher extends Person {
public void teach() {
System.out.println("教学中 ...");
}
}
MathTeacher
package learn_extends.e2;
public class MathTeacher extends Teacher {
@Override
public String getName() {
return "math:" + super.getName();
}
@Override
public void teach() {
System.out.println("我是数学老师");
super.teach();
}
public void draw() {
System.out.println("画图形");
}
}
EnglishTeacher
package learn_extends.e2;
public class EnglishTeacher extends Teacher {
@Override
public String getName() {
return "english:" + super.getName();
}
@Override
public void teach() {
System.out.println("我是英语老师");
super.teach();
}
public void speak() {
System.out.println("听说读写");
}
}
Main
package learn_extends.e2;
public class Main {
private static MathTeacher createObject() {
return new MathTeacher();
}
public static void main(String[] args) {
Person p = createObject();
System.out.println(p.getName());
//p.teach();
//p.draw();
}
}
下边我们来分析一下:
父类引用是Person,决定了它所能执行的方法Person.java 父类中只有getName方法,所以p引用只能.出getName,虽然MathTeacher中还有techer和draw方法,但是都不能执行。
我们再来看调用getName方法后执行那个代码呢,因为对象是MathTeacher
其中还重写了父类的该方法,所以就先在子类中找,刚好有就执行重写后的代码:
结果为:
刚才说到techer和draw方法不能执行,是因为引用是Person,那么如果把引用改为MathTeacher 就可以了。
所以说引用类型控制了执行方法的权限,而对象类型可以控制到底执行那个方法。
代码分析结果如下:
引用类型 p = new 对象类型 | p.方法 | 是否可执行 | 执行结果 |
---|---|---|---|
Person p = new Person() | p.getName() | √ | person |
Person p = new Person() | p.teach() | × | |
Person p = new Person() | p.draw() | × | |
Person p = new Person() | p.speak() | × | |
Person p = new MathTeacher() | p.getName() | √ | math:person |
Person p = new MathTeacher() | p.teach() | × | |
Person p = new MathTeacher() | p.draw() | × | |
Person p = new MathTeacher() | p.speak() | × | |
Person p = new EnglishTeacher | p.getName() | √ | english:person |
Person p = new EnglishTeacher | p.teach() | × | |
Person p = new EnglishTeacher | p.draw() | × | |
Person p = new EnglishTeacher | p.speak() | × | |
MathTeacher p = new MathTeacher() | p.getName() | √ | math:person |
MathTeacher p = new MathTeacher() | p.teach() | √ | 我是数学老师 教学中 … |
MathTeacher p = new MathTeacher() | p.draw() | √ | 画图形 |
MathTeacher p = new MathTeacher() | p.speak() | × | |
EnglishTeacher p = new EnglishTeacher | p.getName() | √ | english:person |
EnglishTeacher p = new EnglishTeacher | p.teach() | √ | 我是英语老师 教学中 … |
EnglishTeacher p = new EnglishTeacher | p.draw() | × | |
EnglishTeacher p = new EnglishTeacher | p.speak() | √ | 听说读写 |
向下转型
需求分析
示例三
目录结构
代码
Person
package learn_extends.e3;
public class Person {
}
Doctor
package learn_extends.e3;
public class Doctor extends Person {
public void rescue() {
System.out.println("进行心肺复苏");
}
}
Student
package learn_extends.e3;
public class Student extends Person {
public void learn() {
System.out.println("好好学习,天天向上");
}
}
Teacher
package learn_extends.e3;
public class Teacher extends Person {
public void teach() {
System.out.println("我在讲课");
}
}
Main
package learn_extends.e3;
import javax.print.Doc;
public class Main {
private static Person[] train() {
Person[] array = new Person[10];
for (int i = 0; i < 5; i++) {
array[i] = new Teacher();
}
array[5] = new Doctor();
for (int i = 6; i < 10; i++) {
array[i] = new Student();
}
return array;
}
public static void main(String[] args) {
Person[] array = train();
for (int i = 0; i < array.length; i++) {
Person p = array[i];
if (p instanceof Doctor) {
System.out.println("下标是 " + i + " 的乘客是医生");
Doctor d = (Doctor)p;
d.rescue();
} else {
//System.out.println("不是医生,冒充医生");
//Doctor d = (Doctor)p;
//d.rescue();
}
}
}
}
结果
不是医生就会类型转换报错: