1. 多态的概述
1.1 多态的概述
-
同一种事物表现出来的多种形态则称为多态。
"俊杰" ==> 班长
"俊杰" ==> 儿子
"俊杰" ==> 父亲
"俊杰" ==> 路人甲
1.2 多态的前提
- 必须有子父类关系或类实现接口关系
- 必须有方法重写
- 必须有父类引用指向子类对象或接口引用指向实现类对象
1.3 多态的格式
- 父类类名 变量名 = new 子类类名();
- 接口名 变量名 = new 接口实现类();
2. 多态案例
// 抽象类:动物父类
abstract class Animal{
public abstract void eat();
public abstract void sleep();
}
// 子类Dog 继承 动物类
class Dog extends Animal{
@Override
public void eat() {
System.out.println("狗吃骨头");
}
@Override
public void sleep() {
System.out.println("狗趴着睡");
}
}
interface Play{
public void playing();
}
class Cat implements Play{
@Override
public void playing() {
System.out.println("和猫玩耍");
}
}
// 人类
class Person{
public void eat() {
System.out.println("人吃饭");
}
}
// 学生类
class Student extends Person{
public void eat() {
System.out.println("学生吃饭");
}
}
public class Demo01 {
public static void main(String[] args) {
// 创建Dog对象
Dog d = new Dog();
// 调用方法
d.eat();
d.sleep();
System.out.println("--------");
// 使用多态形式
Animal a = new Dog();
a.eat();
a.sleep();
// 使用多态形式:创建猫对象
Play p = new Cat();
p.playing();
// 使用多态形式:创建学生对象
Person stu = new Student();
stu.eat();
}
}
3. 多态的注意细节
-
多态的注意事项
- 多态情况下,如果子父类出现同名的成员变量时,访问的是父类的成员变量。
- 多态情况下,如果子父类出现同名的成员方法时,访问的是子类重写后的成员方法
编译特性
成员变量:编译看左边,运行看左边。
成员方法:编译看左边,运行看右边。
成员变量:属于静态绑定
成员方法:属于动态绑定
4. 多态的好处(优点)与弊端(缺点)
-
多态的缺点
- 不能访问子类特有的成员:成员变量和成员方法
-
多态的优点
- 提高了代码的复用性。
- 提高了代码的扩展性。
- 提高了代码的维护性。
5. 多态的使用场景
- 作为方法的形式参数,可以接收更多数据类型的对象。
- 作为方法的返回值类型,可以方法更多的数据类型的对象
6. 多态的转型
- 向上转型:父类引用指向子类对象的过程就是向上转型的结果。
Animal a = new Dog();
- 向下转型:将父类引用强制转换为子类引用的过程
格式:子类类型 变量名 = (子类类型)父类引用;
7. instanceof关键字
- 作用:用来判断多态后父类引用到底指向哪个子类类型的对象。
- 格式:boolean b = 引用变量 instanceof 类名或接口名;
- 注意事项:如果instanceof关键字后面的是类名,则要求引用变量和类之间有子父类关系。
/**
* 抽象类 动物类
*/
public abstract class Animal {
// 成员方法
public abstract void eat();
public abstract void sleep();
}
public class Dog extends Animal implements Play {
@Override
public void eat() {
System.out.println("狗吃肉");
}
@Override
public void sleep() {
System.out.println("趴着睡");
}
public void lookHome() {
System.out.println("老老实实看家");
}
@Override
public void playing() {
System.out.println("狗玩耍的方法");
}
}
public class Cat extends Animal {
@Override
public void eat() {
System.out.println("猫吃鱼");
}
@Override
public void sleep() {
System.out.println("猫躺着睡");
}
public void catchMouse() {
System.out.println("猫捉老鼠");
}
}
public interface Play {
void playing();
}
/*
* 测试类
*/
public class Demo01 {
public static void main(String[] args) {
// 养一只狗对象
Dog d1 = new Dog();
// 喂养狗
/*d1.eat();
d1.sleep();*/
// feedDog(d1);
feedAnimal(d1);
// 再养一只狗
Dog d2 = new Dog();
/*d2.eat();
d2.sleep();*/
// feedDog(d2);
feedAnimal(d2);
// 再养一只狗
Dog d3 = new Dog();
/*d3.eat();
d3.sleep();*/
// feedDog(d3);
feedAnimal(d3);
// 养一只猫
Cat c1 = new Cat();
/*c1.eat();
c1.sleep();*/
// feedCat(c1);
feedAnimal(c1);
// 再养一只猫
Cat c2 = new Cat();
/*c2.eat();
c2.sleep();*/
// feedCat(c2);
feedAnimal(c2);
feedAnimal(new Tiger());
// 调用工厂方法获得一只动物
Animal aa = productAnimal(1); // Animal aa = new Dog()
aa.eat();
aa.sleep();
}
/**
* 工厂方法
* type = 1 狗
* type = 2 猫
*/
public static Animal productAnimal(int type) {
if(type == 1) {
//此次省略一万行代码
return new Dog();
} else if (type == 2) {
return new Cat();
}
return new Tiger();
}
/**
* 喂养动物
*/
public static void feedAnimal(Animal a) { // Animal a = new Tiger();
a.sleep();
a.eat();
// 格式:boolean b = 引用变量 instanceof 数据类型;
boolean b = a instanceof Dog;
if(a instanceof Dog) {
// 格式:子类类型 变量名 = (子类类型)父类引用;
Dog d = (Dog)a;
// 调用子类特有的成员
// d.lookHome();
} else if(a instanceof Cat) {
// 向下转型为Cat
Cat c = (Cat)a;
c.catchMouse();
}
// 判断引用变量a是否实现了指定的接口:Play,如果实现了则返回true,否则false
if(a instanceof Play) {
// 调用狗的playing方法
Play p = (Play)a;
p.playing();
}
}
/*
*//**
* 喂养猫
* @param d
*//*
public static void feedCat(Cat c) {
c.eat();
c.sleep();
}
*//**
* 喂养狗
* @param d
*//*
public static void feedDog(Dog d) {
d.eat();
d.sleep();
}*/
}