目录
一、入门案例
Food类
Animal类
Master类
运行测试
分析
运行结果
问题总结
二、方法的多态
三、对象的多态(重难点/核心)
四个非常重要的知识点(背诵)
举例说明
父类-Animal类
子类-Dog类
子类-Cat类
运行-PolyObject类
运行结果
编辑 分析
改变运行类型
分析
运行结果
举例说明
多态是建立在封装和继承至上的,是面向对象中最难的部分
一、入门案例
主人需要给自己的不同的宠物喂不同的食物
建立Food类(包括子类Bone和Fish),Animal类(包括子类Dog、Cat),Master类
和Poly01(测试运行)
Food类
package com.hspedu.poly_;
public class Food {
private String name;
public Food(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.hspedu.poly_;
public class Fish extends Food{
//需要继承父类的构造器
public Fish(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Bone extends Food{
public Bone(String name) {
super(name);
}
}
Animal类
package com.hspedu.poly_;
public class Animal {
private String name;
public Animal(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
package com.hspedu.poly_;
public class Cat extends Animal{
public Cat(String name) {
super(name);
}
}
package com.hspedu.poly_;
public class Dog extends Animal{
public Dog(String name) {
super(name);
}
}
Master类
package com.hspedu.poly_;
public class Master {
private String name;
public Master(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
//有一个feed方法,完成主人给动物喂食的动作
public void feed(Dog dog, Bone bone){
//dog.getName()继承自Animal的getName;
//fish.getName()继承自Food的getName;
System.out.println("主人" + name + "给小狗"+ dog.getName() + "喂" + bone.getName());
}
public void feed2(Cat cat, Fish fish){
System.out.println("主人" + name + "给小猫"+ cat.getName() + "喂" + fish.getName());
}
}
运行测试
package com.hspedu.poly_;
public class Poly01 {
public static void main(String[] args) {
Master master = new Master("小李");
Dog spike = new Dog("Spike");
Bone bone = new Bone("大骨头");
master.feed(spike,bone);
Cat tom = new Cat("Tom");
Fish fish = new Fish("鱼罐头");
master.feed2(tom,fish);
}
}
上述代码中的
Master master = new Master("小李");
Dog spike = new Dog("Spike");
Bone bone = new Bone("大骨头");
master.feed(spike,bone);
分析
对象引用master调用feed方法,此时需要传入一个Dog类变量和一个Bone类变量,即spike和bone
章节7.3.1基本数据类型的传参机制
//创建 AA 对象 名字 obj
int a = 10;
int b = 20;
AA obj = new AA();
obj.swap(a, b); //调用 swap
swap()方法
public void swap(int a,int b){
}
创建新对象obj,然后创建两个int型变量a,b,然后传参调用
运行结果
问题总结
如果多几个宠物多几种食物就需要一直创建新的类和新的方法,不利于管理和维护
此时就需要多态来解决这个问题
二、方法的多态
package com.hspedu.poly_;
public class PolyMethod {
public static void main(String[] args) {
//方法重载体现多态
A a = new A();
//传入的参数个数不同,调用不同的sum方法
//就是sum方法多重状态的体现
System.out.println(a.sum(10,20));
System.out.println(a.sum(10,20,30));
//方法的重写体现出多态
B b = new B();
//两者会调用不同的say()方法,体现出say()方法的多态
a.say();
b.say();
}
}
class B { //父类
public void say() {
System.out.println("B say() 方法被调用...");
}
}
class A extends B {//子类
public int sum(int n1, int n2) {//和下面 sum 构成重载
return n1 + n2;
}
public int sum(int n1, int n2, int n3) {
return n1 + n2 + n3;
}
public void say() {
System.out.println("A say() 方法被调用...");
}
}
方法重载体现多态: 传入的参数个数不同,调用不同的sum方法,就是sum方法多重状态的体现
方法的重写体现出多态:两者会调用不同的say()方法(一个子类,一个父类),体现出say()方法的多态
三、对象的多态(重难点/核心)
四个非常重要的知识点(背诵)
1.一个对象的编译类型和运行类型可以不一致
2.编译类型在定义对象时就确定了,不能改变,
3.运行类型是可以变化的
4.编译类型看定义时“=”的左边,运行类型看“=”的右边
举例说明
父类-Animal类
package com.hspedu.poly_.objectpoly_;
public class Animal {
public void cry() {
System.out.println("Animal cry()动物在叫...");
}
}
子类-Dog类
package com.hspedu.poly_.objectpoly_;
public class Dog extends Animal{
@Override
public void cry() {
System.out.println("Dog cry()小狗汪汪叫...");
}
}
子类-Cat类
package com.hspedu.poly_.objectpoly_;
public class Cat extends Animal{
@Override//重写的注解
public void cry() {
System.out.println("Cat cry()小猫喵喵叫...");
}
}
运行-PolyObject类
package com.hspedu.poly_.objectpoly_;
public class PolyObject {
public static void main(String[] args) {
Animal animal = new Dog();
animal.cry();
}
}
运行结果
分析
Animal animal = new Dog();
animal的编译类型(javac的时候)是Animal,运行类型(java的时候)是Dog
animal.cry();
调用的是Dog的cry,因为运行时,执行到该行的时候,animal的运行类型是Dog, 所以cry就是Dog的cry
改变运行类型
package com.hspedu.poly_.objectpoly_;
public class PolyObject {
public static void main(String[] args) {
Animal animal = new Dog();
animal.cry();
animal = new Cat();
animal.cry();
}
}
分析
编译类型不变,运行类型变成了Cat,本质是看堆内真正的对象,所以animal.cry()调用的Cat类的方法
运行结果
举例说明
披着羊皮的狼 ,表面是羊(编译类型),实际是狼(运行类型)
披着狼皮的羊,表面是狼(编译类型),实际是羊(运行类型)