文章目录
- 1 多态数组
- 1.1 需求变更
- 1.2 instanceof 介绍
- 1.3 使用 instanceof 完成需求
- 1.4 *完整代码
- 2 多态参数
- 写在最后
1 多态数组
✈️ 多态数组是面向对象中的多态的常用点,我们来看下面这个案例:
编写三个类,Person类、Teacher类、Student类,其中 Teacher 与 Student类 均为 Person类的子类。具体要求如下:
(1)在 Person类 中,包含 name,用于存储人的姓名;
(2)在 Teacher类 中,额外需要一个 salary属性,用于记录老师的月工资;
(3)在Student类 中,额外需要一个 score属性,用于存储学生的成绩;
(4) 以上三个类均需要提供一个 say() 方法,用于展示基本信息;
(5) 录入2个老师以及3个学生的信息,并输出结果。
通过分析需求,我们可以确定继承关系如下图:
🍑 参考代码如下:
为了方便起见,没有编写相应的 set 和 get 方法,只简单实现了构造器。
public class PolyArray {
public static void main(String[] args) {
Person[] person = new Person[5];
// 录入两个老师和三个学生的信息
person[0] = new Teacher("王芳", 4800);
person[1] = new Teacher("陈冰冰", 6500);
person[2] = new Student("霸王龙", 95);
person[3] = new Student("毛毛虫", 98);
person[4] = new Student("臭贝", 88);
// 信息展示
for (int i = 0; i < person.length; i++) {
System.out.println(person[i].say()); // 由多态的特性知,会根据运行类型调用相应的方法
}
}
}
/**
* Person类
*/
class Person{
private String name; // 存储姓名
public Person(String name) {
this.name = name;
}
// 展示信息的方法
public String say(){
return "我是" + name;
}
}
/**
* Teacher类
*/
class Teacher extends Person{
private int salary; // 存储工资
public Teacher(String name, int salary) {
super(name);
this.salary = salary;
}
// 重写 say 方法
@Override
public String say(){
return super.say() + ", " + "薪水是" + salary + "RMB";
}
}
/**
* Student类
*/
class Student extends Person{
private int score; // 记录学生成绩
public Student(String name, int score) {
super(name);
this.score = score;
}
// 重写 say 方法
@Override
public String say(){
return super.say() + ", " + "成绩是" + score;
}
}
🍎 实现结果:
1.1 需求变更
1 小节的功能我们已经通过多态的方式实现了,现在,突然有了个新需求:
(1)在 Teacher 类中添加新方法 teach,用于展示教师授课的行为;
(2)在 Student 类中添加新方法 study,用于展示学生听课的行为。
🍑 根据新的需求,我们分别在 Teach 类 与 Student 类中添加新的方法:
⭐️ Teacher 类:
class Teacher extends Person{
private int salary; // 存储工资
public Teacher(String name, int salary) {
super(name);
this.salary = salary;
}
// 重写 say 方法
@Override
public String say(){
return super.say() + ", " + "薪水是" + salary + "RMB";
}
// 新增加的 teach方法
public void teach(){
System.out.println("我在讲课!");
}
}
⭐️ Student类:
class Student extends Person{
private int score; // 记录学生成绩
public Student(String name, int score) {
super(name);
this.score = score;
}
// 重写 say 方法
@Override
public String say(){
return super.say() + ", " + "成绩是" + score;
}
// 新增 study 方法
public void study(){
System.out.println("我在学习!");
}
}
好啦,现在我们在主函数中调用一下吧!可是出现了如下的状况:
❤️ 回顾下上篇博客的相关知识:多态的特性与向下转型 我们发现了问题:teach
和 study
两个方法在 Person类中没有声明,属于子类的特有方法,不可以通过父类引用去调用子类的特有成员!!! 因此,如果我们想要完成需求的话,就需要使用到向下转型!可是,在上一节中,博主就介绍了:要求父类的引用必须指向的是当前目标类型的对象,才可以进行向下转型!
😗 那么有没有一种方便的办法,让我们判断可不可以进行向下转型呢?当然!下面我们引入 instanceof
关键字。
1.2 instanceof 介绍
🅰️ instanceof
是 Java 的保留关键字,它的作用是测试它左边的对象是否是它右边的类的实例,返回 boolean
的数据类型
值得一提的是: instanceof 实际上是用于判断对象的类型是否为 XX 类型或者 XX类型的 子类型。
🍑 我们来看下面的代码例子,答案在注释,继承关系为 Dog 和 Cat 为 Animal 的子类:
public class Main {
public static void main(String[] args) {
Animal a1 = new Animal();
Animal a2 = new Dog();
Animal a3 = new Cat();
Dog d1 = new Dog();
System.out.println(a1 instanceof Animal); // true
System.out.println(a1 instanceof Dog); // false
System.out.println(a1 instanceof Cat); // false
System.out.println(a2 instanceof Animal); // true
System.out.println(a2 instanceof Dog); // true
System.out.println(a2 instanceof Cat); // false
System.out.println(a3 instanceof Animal); // true
System.out.println(a3 instanceof Dog); // false
System.out.println(a3 instanceof Cat); // true
System.out.println(d1 instanceof Animal); // true
}
}
1.3 使用 instanceof 完成需求
学习完 instanceof
后,我们就可以在主函数中判断是否可以进行向下转型,以此来调用相应的特有方法啦,主函数修改如下:
public class PolyArray {
public static void main(String[] args) {
Person[] person = new Person[5];
// 录入两个老师和三个学生的信息
person[0] = new Teacher("王芳", 4800);
person[1] = new Teacher("陈冰冰", 6500);
person[2] = new Student("霸王龙", 95);
person[3] = new Student("毛毛虫", 98);
person[4] = new Student("臭贝", 88);
// 信息展示
for (int i = 0; i < person.length; i++) {
System.out.println(person[i].say()); // 先展示信息
if(person[i] instanceof Teacher){ // 如果是老师
((Teacher) person[i]).teach();
} else if(person[i] instanceof Student){ // 如果是学生
((Student) person[i]).study();
} else { // 其他情况
System.out.println("Person[" + i + "] 的类型不兼容!");
}
}
}
}
🍎 来看看运行结果:
1.4 *完整代码
public class PolyArray {
public static void main(String[] args) {
Person[] person = new Person[5];
// 录入两个老师和三个学生的信息
person[0] = new Teacher("王芳", 4800);
person[1] = new Teacher("陈冰冰", 6500);
person[2] = new Student("霸王龙", 95);
person[3] = new Student("毛毛虫", 98);
person[4] = new Student("臭贝", 88);
// 信息展示
for (int i = 0; i < person.length; i++) {
System.out.println(person[i].say()); // 先展示信息
if(person[i] instanceof Teacher){ // 如果是老师
((Teacher) person[i]).teach();
} else if(person[i] instanceof Student){ // 如果是学生
((Student) person[i]).study();
} else { // 其他情况
System.out.println("Person[" + i + "] 的类型不兼容!");
}
}
}
}
/**
* Person类
*/
class Person{
private String name; // 存储姓名
public Person(String name) {
this.name = name;
}
// 展示信息的方法
public String say(){
return "我是" + name;
}
}
/**
* Teacher类
*/
class Teacher extends Person{
private int salary; // 存储工资
public Teacher(String name, int salary) {
super(name);
this.salary = salary;
}
// 重写 say 方法
@Override
public String say(){
return super.say() + ", " + "薪水是" + salary + "RMB";
}
// 新增加的 teach方法
public void teach(){
System.out.println("我在讲课!");
}
}
/**
* Student类
*/
class Student extends Person{
private int score; // 记录学生成绩
public Student(String name, int score) {
super(name);
this.score = score;
}
// 重写 say 方法
@Override
public String say(){
return super.say() + ", " + "成绩是" + score;
}
// 新增 study 方法
public void study(){
System.out.println("我在学习!");
}
}
2 多态参数
✈️ 即方法定义的形参类型为父类类型,实参类型允许为子类类型。
Tips:其实就和之前说过的喂养宠物的问题一样!我们来回顾一下,并进行讲解:
尝试用你现有的知识,编写 Food类、 Animal类,并按照下图编写其相应的子类,提供必要的属性。最后,编写一个 Master类,包含喂养宠物的 feed() 方法。请你随意录入一组信息,并测试功能是否实现。
🍑 代码如下:
- ⭐️ Food类:
public class Food {
private String name; // 食物名称
public Food(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
- ⭐️ Fish类:
public class Fish extends Food{
public Fish(String name) {
super(name);
}
}
- ⭐️ Bone类:
public class Bone extends Food{
public Bone(String name) {
super(name);
}
}
- ⭐️ Animal类:
public class Animal {
private String name; // 动物名字
public Animal(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
- ⭐️ Dog类:
public class Dog extends Animal{
public Dog(String name) {
super(name);
}
}
- ⭐️ Cat类:
public class Cat extends Animal{
public Cat(String name) {
super(name);
}
}
- ⭐️ Master类:
public class Master {
private String name; // 名字
public Master(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void feed(Animal animal, Food food){
System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
}
}
- ⭐️ Main测试类:
public class Main {
public static void main(String[] args) {
// 领养宠物
Dog dog = new Dog("大黄狗");
Cat cat = new Cat("小花猫");
// 登记主人信息
Master master = new Master("祢豆子");
// 提供食物
Bone bone = new Bone("炸排骨");
Fish fish = new Fish("小黄鱼");
// 喂养大黄狗
master.feed(dog, bone);
// 喂养小花猫
master.feed(cat, fish);
}
}
🍎 我们重点关注 Master 类中的这段代码:
public void feed(Animal animal, Food food){
System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());
}
❤️ 在这里我们 把参数列表设置成了父类类型,当使用时其实参可以为子类类型, 即 Animal animal
可以传入一个 Dog类
的参数(Dog为Animal的子类),而方法根据动态绑定机制(属性看编译类型,方法看运行类型)判断这个是属于何种运行类型,比如 Dog类
,则在方法中调用 Dog类
的方法的 getName()
(没有则在父类中查找),这便是一种多态参数的体现。
❤️ 在实际应用中,我们常常 在方法体里进行对象类型的判断,比如,在 feed
方法中,我们可以判断 animal
到底是什么类型,如果是 Dog
类型,则向下转型,调用相应的方法,比如发出 “汪汪汪~”的声音,以此类推。
🍌 实现结果: