一、多态的来历
我们先来了解一个业务场景:请设计一个系统,描述主人喂养宠物的场景,首先在这个场景当中应该有”宠物对象“,“宠物对象”应该有一个吃的行为,另外还需要一个“主人对象”,主人应该有一个喂的行为,请看代码:
//小猫
public class Cat{
String name;
public Cat(String name) {
this.name=name;
}
public void eat() {
System.out.println(this.name+"正在吃鱼");
}
}
//主人
public class Person {
String name;
public Person(String name) {
this.name=name;
}
public void feed(Cat cat) {
System.out.println(this.name+"拿出来了好多小鱼");
cat.eat();
System.out.println(cat.name+"十秒钟吃了10条小鱼");
}
}
//测试类
public class Test1 {
public static void main(String[] args) {
Cat cat = new Cat("小花");
Person person1= new Person("小明");
person1.feed(cat);
}
}
测试结果:
现在我们已经创建了一个喂养宠物的场景,但是我们想一想,假如家里又来了几只宠物你会怎么办
与小猫类的代码一样,我们可以创建小狗类,小猪类,小牛类........
public class Pig {
String name;
...
}
//吃的行为
public void eat(){
...
}
}
public class Dog {
String name;
...
}
//吃的行为
public void eat(){
...
}
}
public class Cow {
String name;
...
}
//吃的行为
public void eat(){
...
}
}
如果主人想要喂养它们,我们还需要主人的源代码,这是让程序员无法容忍的,如果这个人养了上千种动物,就意味着你需要增改上千次
//主人
public class Person {
String name;
public Person(String name) {
this.name=name;
}
public void feed(Cat cat) {
System.out.println(this.name+"拿出来了好多小鱼");
cat.eat();
System.out.println(cat.name+"十秒钟吃了10条小鱼");
}
public void feed(Dog dog) {
System.out.println(this.name+"拿出来了好多骨头");
dog.eat();
System.out.println(dog.name+"十秒钟吃了10根骨头");
}
//feed pig.....
//feed cow..........这个博主有点小懒
}
//测试类
public class Test1 {
public static void main(String[] args) {
Cat cat = new Cat("小花");
Dog dog = new Dog("旺财");
Person person1= new Person("小明");
person1.feed(cat);
person1.feed(dog);
//person1.feed(pig) person1.feed(Cow);
System.out.println(" ");
System.out.print("博主省略了猪和牛,就知道多繁琐了");
}
}
测试结果:
那么如何解决这个问题呢????????你猜对了-------就是多态!
我们都知道小猫小狗...都属于宠物,也就是说宠物类是单个宠物的父类
请看代码:
public class Pet {
String name;
//吃的行为
public void eat(){
}
}
//小猫
public class Cat extends Pet{
public Cat(String name) {
this.name=name;
}
public void eat() {
System.out.println(this.name+"正在吃鱼");
}
}
//小狗
public class Dog extends Pet{
public Dog(String name) {
this.name=name;
}
public void eat() {
System.out.println(this.name+"正在啃骨头");
}
}
//主人
public class Person {
String name;
public Person(String name) {
this.name=name;
}
public void feed(Pet pet) {
System.out.println("主人正在喂食");
pet.eat();
System.out.println("主人喂食完毕");
}
}
//测试类
public class Person {
String name;
public Person(String name) {
this.name=name;
}
public void feed(Pet pet) {
System.out.println("主人正在喂食");
pet.eat();
System.out.println("主人喂食完毕");
}
}
测试结果
与上面的结果是等价的,在主人类中我们节省了很多力气
总结,上面的程序代码中,主人(Person类)中的feed(Pet pet)的参数类型定义为更加抽象的Pet类型,而不是具体的Cat宠物,或者Dog宠物。那假如说主人又养了一个小牛,我们要增加一个”小牛类“,然后Pig 继承宠物类Pet,并重写eat()方法,然后修改一下测试类就行了,整个过程我们不需要修改Person类,只是额外增加了一个新的类
public class Pig extends Pet{
public Pig(String name) {
this.name=name;
}
public void eat() {
System.out.println(this.name+"小猪正在进食");
}
}
//测试类
public class Test1 {
public static void main(String[] args) {
Cat cat = new Cat("小花");
Dog dog = new Dog("旺财");
Pig pig = new Pig("猪哼哼");
Person person1= new Person("小明");
person1.feed(cat);
person1.feed(dog);
person1.feed(pig);
}
}
测试结果:
从上面例子表可以感受到多态的使用大大节省了内存与算力!
二、那究竟什么是多态?
多态是同一个行为具有多个不同表现形式和形态的能力
三、多态实现的必要条件
1.子类必须继承父类
2.必须有重写
3.父类引用指向子类对象------>向上转型
我在下面将采用内存图的形式向你展示,多态的过程,方便你理解
我们首先要知道,多态语句的构成
Pet cat=new Cat();
//Pet:类名
//cat:变量
//new:关键字
//Cat():构造器
Pet cat=new Cat();
会在堆区生成一个Pet对象 cat存储Pet对象的地址,而不是存储Cat对象的地址
重点:父类方法被重写之后,会生成一个指针指向子类重写的方法
//小猫类
public class Cat extends Pet{
public Cat(String name) {
this.name=name;
}
public void eat() {
System.out.println(this.name+"正在吃鱼");
}
public void jump() {
System.out.println("小猫跳的很高");
}
}
//父类
public class Pet {
String name;
//吃的行为
public void eat() {
}
}
//主人
public class Person {
String name;
public Person(String name) {
this.name=name;
}
public void feed(Pet pet) {
System.out.println("主人正在喂食");
pet.eat();
System.out.println("主人喂食完毕");
}
}
//测试类
public class Test1 {
public static void main(String[] args) {
Pet cat = new Cat("小花");
cat.eat();
}
}
结果:
接下来我们来画一下内存图
看到 cat变量指向的是Pet类,Cat对eat()方法进行了重写,指针指向,所以才能调取到Cat类中的eat()方法
那就有人会问了 能不能调用jump()方法呢
试一试!
答案是不行,因为我们观察内存图,jump()方法并未被调取,除非jump()方法是对父类方法的重写!
四、测试练习!
//父类
public class A {
public String show(D obj) {
return "A and D";
}
public String show(A obj) {
return "A and A";
}
}
//各子类
public class B extends A{
public String show(Object obj) {
return "B and B";
}
public String show(A obj) {
return "B and A";
}
}
public class D extends B{
}
public class C extends B{
}
//测试类
public class Test {
public static void main(String[] args) {
A a1=new A();
A a2 = new B();
B b = new B();
C c= new C();
D d= new D();
System.out.println(a1.show(b));
System.out.println(a1.show(c));
System.out.println(a1.show(d));
System.out.println(a2.show(b));
System.out.println(a2.show(c));
System.out.println(a2.show(d));
System.out.println(b.show(b));
System.out.println(b.show(c));
System.out.println(b.show(d));
}
}
请你说出测试结果!!!!!最好用画内存的方法,去解决问题,更加清晰!!!
测试结果: