面向对象高级(多态&final&抽象类)
今天我们继续学习面向对象的语法知识,我们今天学习的主要内容是:多态、final、抽象。
学会这些语法知识,可以让我们编写代码更灵活,代码的复用性更高。
一、多态
接下来,我们学习面向对象三大特征的的最后一个特征------多态。
1.1 多态概述
什么是多态?
多态是在继承/实现情况下的一种现象,表现为:对象多态、行为多态。
比如:Teacher和Student都是People的子类,代码可以写成下面的样子

public class People {
String name = "父类";
public void run(){
System.out.println("人会跑");
}
}
public class Teacher extends People{
String name = "老师";
@Override
public void run() {
System.out.println("老师跑的比较慢~~~");
}
// 独有功能
public void teach(){
System.out.println("老师教授Java~~~");
}
}
public class Student extends People{
String name = "学生";
@Override
public void run() {
System.out.println("学生跑的飞快~~~");
}
// 独有功能
public void study(){
System.out.println("学生好好学习~~~");
}
}
public class Test1 {
public static void main(String[] args) {
// 目标:认识多态
People p1 = new Teacher();
System.out.println(p1.name); // 识别技巧: 编译看左边, 运行看右边
p1.run(); // 识别技巧: 编译看左边, 运行看右边
People p2 = new Student();
System.out.println(p2.name); // 识别技巧: 编译看左边, 运行看右边
p2.run(); // 识别技巧: 编译看左边, 运行看右边
}
}
注意:
多态的前提: 有继承/实现关系;存在父类引用子类对象;存在方法重写。
多态的一个注意事项: 多态是对象、行为的多态,Java中的属性(成员变量)不谈多态。
1.2 多态的好处
各位同学,刚才我们认识了什么是多态。那么多态的写法有什么好处呢?
在多态形式下,右边的对象是解耦合的,更便于扩展和维护。
-
怎么理解这句话呢?比如刚开始p1指向Student对象,run方法执行的就是Student对象的业务;假如p1指向Teacher对象 ,run方法执行的自然是Teacher对象的业务,右边对象可以随时切换,后续业务随机改变。
-

定义方法时,使用父类类型作为形参,可以接收一切子类对象,扩展性更强,更便利。
public class Test2 {
public static void main(String[] args) {
// 目标:掌握使用多态的好处
// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
People p1 = new Student();
p1.run();
System.out.println("==================");
Teacher t = new Teacher();
go(t);
Student s = new Student();
go(s);
}
// 好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
// 参数People p既可以接收Student对象,也能接收Teacher对象。
public static void go(People p){
System.out.println("开始------------------------");
p.run();
System.out.println("结束------------------------");
}
}
1.3 类型转换
虽然多态形式下有一些好处,但是也有一些弊端。
在多态形式下,不能调用子类特有的方法,比如在Teacher类中多了一个teach方法,在Student类中多了一个study方法,这两个方法在多态形式下是不能直接调用的。

多态形式下不能直接调用子类特有方法,但是转型后是可以调用的。
这里所说的转型就是把父类变量转换为子类类型。

public class Test2 {
public static void main(String[] args) {
// 目标:掌握使用多态的好处
// 好处1:可以实现解耦合,右边对象可以随时切换,后续业务随机改变
People p1 = new Student();
p1.run();
// p1.study(); // 多态形式下,不能调用子类特有的方法
// 想要调用就需要强制类型转换
Student s1 = (Student) p1;
s1.study();
//强制类型转换可能存在的问题:编译阶段有继承或实现关系就可以强制, 但是运行时可能会出现类型转换异常
// Teacher t1 = (Teacher) p1; // 运行时: ClassCastException 类型转换异常
System.out.println("==================");
Teacher t2 = new Teacher();
go(t2);
Student s2 = new Student();
go(s2);
}
//好处2:可以使用父类类型的变量作为形参,可以接收一切子类对象。
public static void go(People p){
System.out.println("开始------------------------");
p.run();
System.out.println("结束------------------------");
}
}
强转前,Java建议:
使用instanceof关键字,判断当前对象的真实类型,再进行强转
p instanceof Student ==> 判断当前对象是否真实类型或者子类
格式如下:
//如果p接收的是子类对象
if(父类变量 instanceof 子类){
//则可以将p转换为子类类型
子类 变量名 = (子类)父类变量;
}

如果类型转换错了,就会出现类型转换异常ClassCastException,比如把Teacher类型转换成了Student类型.

关于多态转型问题,我们最终记住一句话:原本是什么类型,才能还原成什么类型