1500字范文,内容丰富有趣,写作好帮手!
1500字范文 > 【JavaSE】面向对象之多态 向上转型与向下转型

【JavaSE】面向对象之多态 向上转型与向下转型

时间:2020-08-13 16:07:54

相关推荐

【JavaSE】面向对象之多态 向上转型与向下转型

本专栏为JavaSE的学习笔记及相关项目,专栏长期免费更新 ❤️ ❤️ ❤️

❤️ 个人主页:Nezuko627 欢迎来访~~~

⭐️往期回顾:

【JavaSE】继承中内存发生了什么变化?这篇文章带你深究继承本质,一次搞懂~【JavaSE】面向对象之封装

文章目录

1 多态引入2 多态2.1 多态的具体体现(方法多态与对象多态)2.2 编译类型与运行类型在程序中的体现 3 使用多态优化4 向上转型与向下转型4.1 多态的向上转型4.2 多态的向下转型 写在最后

1 多态引入

✈️ 我们来看这样一个案例,在我们的生活中,有很多人都会选择养宠物。对于不同的动物,我们需要喂它们不同的食物:

尝试用你现有的知识,编写 Food类、 Animal类,并按照下图编写其相应的子类,提供必要的属性。最后,编写一个 Master类,包含喂养宠物的 feed() 方法。请你随意录入一组信息,并测试功能是否实现。

在前面的两节中,我们学习了封装与继承,我们很容易想到,将 Food类 、 Animal类 作为父类,Fish类 、 Bone类 与 Dog类 、 Cat类 分别作为其子类。根据要求,我们编写代码如下:

⭐️ 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(Dog dog, Bone bone){// 给小狗吃骨头System.out.println("主人 " + name + " 给 " + dog.getName() + " 吃 " + bone.getName());}// 给小猫喂食public void feed(Cat cat, Fish fish){// 给小猫吃鱼System.out.println("主人 " + name + " 给 " + cat.getName() + " 吃 " + fish.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类 中重载了两个 feed() 方法,分别用于喂养小狗和小猫。试想一下,如果 Master 是一个对养宠物的极度爱好者,她领养了 100多只宠物!!! 那如果需要完成喂养宠物,岂不是需要在 Master类 中定义上百种方法!!!!

可见,这样处理问题,虽然结果是可行的,但是代码复用率太低,且非常不利于管理与维护。因此,我们引入面向对象编程中的多态相关内容(是不是很理所当然?)

2 多态

🍑多态的介绍:多态是指方法或对象具有多种形态。是面向对象的第三大特征,多态是建立在封装和继承基础之上的。

2.1 多态的具体体现(方法多态与对象多态)

⭐️star1:方法的重载体现多态

在下面的例子中我们通过不同参数个数去调用sum方法,就会调用不同的方法。这对sum方法来说,就是多态的体现。来看代码:

public class PolymorphicMethod {public static void main(String[] args) {// 方法的重载,体现了多态B b = new B();System.out.println(b.sum(1, 2)); // 3System.out.println(b.sum(1, 2, 3)); // 6}}class B {// 两个 sum 方法互相构成重载!public int sum(int num1, int num2){return num1 + num2;}public int sum(int num1, int num2, int num3){return num1 + num2 + num3;}}

⭐️star2:方法的重写体现多态

在下面的例子中,我们创建了两个类,A为父类,B为子类,两者提供的say方法不同,构成了方法的重写。在主方法中,因为对象不同,调用的同名方法也不同,这就是多态的另一种体现。代码如下:

public class PolymorphicMethod {public static void main(String[] args) {// 方法的重写,体现了多态A a = new A();B b = new B();a.say(); // A 类的 say 被调用了b.say(); // B 类的 say 被调用了}}class A{public void say(){System.out.println("A 类的 say 被调用了");}}class B extends A{// 该类为 A 的子类// 重写say方法public void say(){System.out.println("B 类的 say 被调用了");}}

⭐️star3:对象的多态(重点、核心)

在对象的多态方面我们需要记住下面这四个原则

❤️一个对象的编译类型和运行类型可以不一致❤️编译类型在定义对象时就确定了,不能改变;❤️运行类型是可以变化的❤️ 编译类型看 = 的左边,而运行类型看 = 的右边。

🍑 比如,在我们第 1 小节讲的例子中,DogCat均是Animal的子类,有如下代码,解释见注释:

// animal 编译类型是 Animal,运行类型是 DogAnimal animal = new Dog();// animal 运行类型变成了 Cat,但是编译类型没有改变animal = new Cat();

2.2 编译类型与运行类型在程序中的体现

✈️ 我们将第 1 节的部分代码进行重构,得到下面这些代码(为了便于体会多态,我们只取 Animal 、 Cat、 Dog 、Main四个类):

⭐️ Animal类:

public class Animal {public void say(){System.out.println("I' m Animal!");}}

⭐️ Dog类:

public class Dog extends Animal{public void say(){System.out.println("I'm Dog!");}}

⭐️ Cat类:

public class Cat extends Animal{public void say(){System.out.println("I'm Cat!");}}

⭐️ Main测试类:

public class Main {public static void main(String[] args) {// animal 编译类型为 Animal 运行类型为 DogAnimal animal = new Dog();// 调用方法时 依据 运行类型animal.say(); // I'm Dog!// 更改运行类型为 Catanimal = new Cat();animal.say(); // I'm Cat!// 更改运行类型为 Animalanimal = new Animal();animal.say(); // I'm Animal!}}

🍑 运行结果如下:

3 使用多态优化

✈️ 在第 1 小节,我们聊过,在Master类中定义许多个feed方法来处理喂养宠物的问题,虽然能够解决,但是不利于代码的维护与管理。我们现在已经学习了多态,考虑用多态去优化feed方法,改动如下:

public void feed(Animal animal, Food food){System.out.println("主人 " + name + " 给 " + animal.getName() + " 吃 " + food.getName());}

🍑 在改动中,animal 的编译类型是 Animal,可以接收 Animal 的子类对象;同理,food 的编译类型是 Food,同样可以接收 Food 的子类对象。我们成功将两个分别喂养猫和狗的 feed 方法,通过多态压缩成了一个,有利于我们对代码进行管理和维护,岂不美哉?

4 向上转型与向下转型

4.1 多态的向上转型

1️⃣向上转型的本质父类的引用指向了子类的对象。

2️⃣语法:

父类类型 引用名 = new 子类类型();

3️⃣特点:可以调用父类的所有可访问成员(遵循相应的访问权限),但是,不能调用子类的特有成员,而运行效果则需要看子类的具体实现。

🍑 我们来看下面这段代码,当我们声明一个 编译类型为Animal运行类型为Cat的对象animal时,由于,catchMouse()Cat类的特有成员,所有我们不能调用。say()方法在Animal类中存在,并不是子类所特有的,因此我们可以调用到say(),在Cat类中我们重写了say()方法,所有实际运行的时候,使用是Cat类中的say()方法。

class Animal{public void say(){System.out.println("Animal");}}class Cat extends Animal{public void say(){System.out.println("Cat");}// 特有成员public void catchMouse(){System.out.println("猫抓老鼠");}}public class Main {public static void main(String[] args) {Animal animal = new Cat();animal.say(); // Cat}}

4.2 多态的向下转型

1️⃣语法:

子类类型 引用名 = (子类类型)父类引用;

2️⃣注意事项:

只能强制转换父类的引用,不能强制转换父类的对象;要求父类的引用必须指向的是当前目标类型的对象;可以调用子类类型中的所有成员。

❤️Tips:其实能否向下转型,我们本质上,只需要看其 new 的类型,也就是运行类型,是否为要被转换成的目标编译类型。

🍑 我们只需将 4.1 中的代码稍加修改(真的是一点点!),就可以使animal访问到Cat特有成员catchMouse()方法!

class Animal{public void say(){System.out.println("Animal");}}class Cat extends Animal{public void say(){System.out.println("Cat");}// 特有成员public void catchMouse(){System.out.println("猫抓老鼠");}}public class Main {public static void main(String[] args) {Animal animal = new Cat();// 编译类型为 Animal 的引用,不能访问 Cat 特有成员// 我们需要向下转型,使其可以访问 Cat 特有成员 catchMouse() 方法Cat cat = (Cat)animal;cat.catchMouse(); // 猫抓老鼠}}

写在最后

🌟以上便是本文的全部内容啦,后续内容将会持续免费更新,如果文章对你有所帮助,麻烦动动小手点赞 + 收藏 + 关注,非常感谢 ❤️ ❤️!

如果有问题,欢迎私信或者评论区!

共勉:“其实一直陪伴你的,是那个了不起的自己。”

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。