1.什么是多态
顾名思义,多态就是事物的多种形态。简单来说就是“同一个接口,不同的实现。”
- 多态的表现形式:父类类型 对象名=new 子类类型();
- 多态的前提:
2.多态的使用场景
在学生管理系统中,我们会有学生类型,老师类型,管理员类型,在每个成员使用之前,都必须注册账号。
//注册方法
public boolean register(Student s){
}
在这里如果我们注册方法的形参是Student类型的话,那么同样也需要形参是Teacher、Administrator的方法,增加了代码的复用性,只有形参不同,而需要的注册功能是相同的,还得再写一个方法。那么我们可以利用多态来解决这种问题。
例如:创建一个父类Person
public class Person {
private String name;//姓名
private String username;//账号名
private String password;//密码
public Person() {
}
public Person(String name, String username, String password) {
this.name = name;
this.username = username;
this.password = password;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getUsername() {
return username;
}
public void setUsername(String username) {
this.username = username;
}
public String getPassword() {
return password;
}
public void setPassword(String password) {
this.password = password;
}
}
在创建子类:Student、Teacher
public class Student extends Person {
public Student(){
super();
}
public Student (String name, String username, String password){
super( name, username, password);
}
}
public class Teacher extends Person {
public Teacher(){
super();
}
public Teacher(String name, String username, String password){
super( name, username, password);
}
}
测试类:Test
public class Test {
public static void main(String[] args) {
Student s =new Student("张三","zhang","123456");
Teacher t =new Teacher("李四","li","456789");
//注意下面的register方法的形参是Person类型的,而我们这里穿过去的实参分别是Student、Teacher类型的
register(s);
register(t);
}
//注册方法
public static void register(Person p){
System.out.println("姓名是"+p.getName()+"注册成功账号是:"+p.getUsername()+",密码是:"+p.getPassword());
}
}
输出结果:

通过上面的例子,我们不难看出来利用父类Person作为register作为形参,可以接受子类的所有对象,这样我们解决了一开始的问题。
方法的形参是父类,就可以接受子类所有的对象。
3.多态调用成员的特点
- 变量调用:编译看左边,运行也看左边。
在java文件编译成class文件时,先看父类中有没有这个变量,如果有那就可以编译成功,反之,则不能。
运行看左边:在代码最后的运行结果用的是父类当中的该变量,并非子类。
- 方法调用:编译看左边,运行看右边。
编译看左边:先看父类中有没有这个方法,如果有就编译成功,没有则失败。
运行看左边:在代码真正用的是子类当中的方法。如果子类没有重写父类当中的方法,那就是用父类。
变量调用例子:先了解变量编译看左边
创建父类Person、子类Student
public class Person {
String name;
}
public class Student extends Person {
String work="学习";
}
测试:Test
public class Test {
public static void main(String[] args) {
Person p=new Student ();
/*编译看左边:因为name是父类Person中的变量,所以下面p.name能够编译成功
而s.name就不会编译成功,会显示红色报错。
*/
String Name =p.name;
String Name1 =s.name;//编译器在这里会高亮报错
//同样Student 中特有的子类work也无法编译成功
String work=s.work;
}
}
变量运行也看左边:
创建父类Person、子类Student
public class Person {
String name="张三";
}
public class Student extends Person {
String name="李四";
}
测试:Test
public class Test {
public static void main(String[] args) {
Person p=new Student ();
System.out.println(p.name);
}
}
输出结果:
最后运行结果是父类中的name。
多态方法调用的例子类似,可以自己尝试。
4.多态的优缺点
先说优点:
- 优点
通过目录2中代码,我们已经可以看出优点1,接下来举个例子来体现优点2。
例如:创建一个父类Person
public class Person {
public void work(){
System.out.println("每个人都需要工作");
}
}
子类Student、Teacher
public class Student extends Person {
@Override
public void work(){
System.out.println("学生的工作是学习");
}
}
public class Teacher extends Person {
@Override
public void work(){
System.out.println("老师的工作是教书");
}
}
测试:Test
public class Test {
public static void main(String[] args) {
Student s =new Student();
Teacher t =new Teacher();
s.work();
t.work();
}
}
输出结果:

所以这个例子我们可以知道优点2。
再了解过优点后,我们来看一下缺点。
缺点:多态下不能使用子类特有的功能。
此缺点下面会有破解方案
例子:创建父类对象Person
public class Person {
public void work(){
System.out.println("工作");
}
}
子类Student、Teacher
public class Student extends Person {
public void study(){
System.out.println("我要好好学习!!!");
}
}
public class Teacher extends Person {
public void teach(){
System.out.println("教书育人");
}
}
测试Test:
public class Test {
public static void main(String[] args) {
Person p1=new Student ();
Person p2=new Teacher();
/*study、teach分别是子类p1、p2中特有的功能,由于他们的父类Person中没有,
所以下面两行代码是会报错的!!!*/
p1.sutdy;
p2.teach;
}
}
5.多态当中的类型转换
- 自动类型转换(从子到父):又称为向上转型,子类对象自动转换为父类类型(小变大)。
- 强制类型转换(从父到子):又称为向下转型,子类 对象变量=(子类)父类类型的变量
格式例子:
Person p = new Student();
Student s =(Student)p;
在目录4中了解到多态使用的缺点,我们可以通过强制类型转换来解决这个问题:
父类、子类与目录4当中缺点的一致,只有Test类不同。
测试Test:
public class Test {
public static void main(String[] args) {
Person p1=new Student ();
Person p2=new Teacher();
Student s=(Student)p1;
Teacher t=(Teacher) p2;
s.study();
t.teach();
}
}
输出结果:

不难看出再通过强制类型转换后,我们可以使用子类当中特有的功能。
注意:
| 间接父类 爷爷 | 直接父类 爸爸 | 子类 儿子 |
我们在创建爸爸的对象,赋值给了爷爷类型。代码:Ye ye = new Ba();
再进行强制转换时,只能将爷爷强转到爸爸类型,不能转成儿子类型。
6.instanceof关键字
所以接下来我们引入instanceof关键字,用于判断多态中是否能进行强转。
public class Test {
public static void main(String[] args) {
// 创建爸爸对象,赋值给爷爷类型
Ye ye = new Ba();
// 使用instanceof判断能否转换
if (ye instanceof Ba) {
System.out.println("可以转成爸爸类型");
Ba ba = (Ba) ye; // 强制转换
ba.work(); // 调用爸爸特有方法
}
if (ye instanceof Er) {
System.out.println("可以转成儿子类型");
Er er = (Er) ye;
er.play();
} else {
System.out.println("不能转成儿子类型");
}
}
}
// 爷爷类
class Ye {
public void speak() {
System.out.println("爷爷");
}
}
// 爸爸类
class Ba extends Ye {
public void work() {
System.out.println("爸爸在工作");
}
}
// 儿子类
class Er extends Ba {
public void play() {
System.out.println("儿子在玩耍");
}
}
输出结果:

回到开头的注册系统,正是因为用了多态,我们只写了一个 register(Person p) 方法,就能处理所有类型的人员注册。如果不用多态,Student、Teacher、Admin 各写一个方法,代码会臃肿成什么样?这只是一个小例子,在日常开发中我们也会用很多使用多态的场景。
希望可以帮助你理解多态。


