面向对象学习19 - 多态性

多态性的理解

一个事物的多种形态

Java中多态性的体现

代码示例

public class Person(){
    String name;
    int age;
    public void eat(){
        //吃饭方法之一
    }
    public void sleep(){
        //睡觉方法之一
    }
}

public class Man extends Person(){
    boolean isSmoking;
    public void eat(){
        //吃饭方法之二
    }
    public void sleep(){
        //睡觉方法之二
    }
    public void earnMoney(){
    }
}
public class Woman extends Person(){
    boolean isBeauty;
    public void eat(){
        //吃饭方法之三
    }
    public void sleep(){
        //睡觉方法之三
    }
    public void goShopping(){
    }
}

public class PersonTest{
    public static void main(String[] args){
        //多态性之前的情况
        Person p1 = new Person();
        Man m1 = new Man();
        //多态性
        Person p2 = new Man();
    }
}

形如 Person p2 = new Man();的情况就是多态

父类的引用指向子类的对象。(或者也可以说是子类的对象赋给父类的引用。)

多态性的应用:虚拟方法调用

在多态的场景下,调用方法时
编译时,认为方法时左边声明的父类的类型的方法。(即被重写的方法)
执行时,实际执行的是子类重写的方法。
简称为:编译看左边,运行看右边

多态性使用前提

1、要有继承关系;
2、要有方法的重写;

多态的适用性

适用于方法,不适用于属性

多态的好处与弊端

示例

class Animal{
    public void eat(){
        System.out.println("动物吃饭");
    public void jump(){
        System.out.println("动物跳");
    }
}

class Cat extends Animal{
    public void eat(){
        System.out.println("猫吃鱼");
    }
    public void jump(){
        System.out.printlb("猫都会轻功");
    }
    public void catchMouth(){
        System.out.println("猫抓老鼠");
    }
}

class Dog extends Animal{
    public void eat(){
        System.out.println("狗吃骨头");
    }
    public void jump(){
        System.out.println("狗急跳墙");
    }
    public void guardDoor(){
        System.out.println("狗看门");
    }
}

public class AnimalTest{
    public static void main(String[] args){
        AnimalTest test = new AnimalTest();
        test.adopt(new Animal());
        test.adopt(new Dog());
        test.adopt(new Cat());
    }
    public void adopt(Animal animal){
        animal.eat();
        animal.jump();
    }
}

好处

使用父类做方法的形参,是多态使用最多的场合,即使增加了新的子类,
方法也无需改变,提高了扩展性,符合开闭原则。
[开闭原则OCP]
对扩展开放,对修改关闭
通俗解释:软件系统中的各种组件:如模块(Modoules),类(classes)以及功能
(Functions)等,应该在不修改现有代码的基础上,引入新功能。
极大的减少了代码的英语,不需要定于多少重载方法。

弊端

Person p2 = new Man();
针对于创建的对象,在内存中是否加载了Man类中声明了特有的属性和方法?加载了!
能不能调用Man中加载的特有的属性和方法?不能!

向下转型

示例

public class PersonTest{
    public static void main(String[] args){
        Person p1 = new Man();
        //不能直接调用子类特有的结构
        p1.earnMoney();
        System.out.println("p1.isSmoking");
        
        //向下转型
        Man m1 = (Man)p1;//m1和p1在堆空间的地址是相同的,是同一个对象
        m1.earnMoney();
        System.out.println(m1.isSmoking());

        Person p2 = new Woman();
        Man m2 = (Man)p2;//这里类型转换异常

        //建议在向下转型之前,使用instanceOf进行判断,避免出现类型转换异常
        if(p2 instanceOf Man){
            Man m2 = (Man)p2;
            m2.earnMoney();
        }
    }
}

类比基本数据类型

较高级的基本数据类型转换成较低级的基本数据类型时需要强制类型转换
反之会进行自动类型提升。
类似的 父类转换成子类使用同样形式的向下转型
反之则为多态

多态性练习

题目

定义三个类,父类GeometricObject代表几何形状,子类Circle代表圆形,
MyRectangle代表矩形。
定义一个测试类GeoMetriTest,
编写equalsArea方法测试两个对象的面积是否相等。
编写displayGeometricObject方法显示对象的面积。

代码(省略get、set方法)

public class GeometricObject{
    protected String color;
    protected double weight;//UML图中,protected用#表示
    protected GeometricObject(String color,double weight){
        this.color = color;
        this.weight = weight;
    }
    Public double findArea(){
        return 0.0;
    }
}

public class Circle extends GeometricObject{
    private double radius;//半径
    public Circle(String color,double weight,double radius){
        super(color.weight);
        this.radius = radius;
    }
    @Override
    public double findArea(){
        return 3.14 * radius * radius;
    }
}

public class MyRectangle extends GeometricObject{
    private double width;//宽
    private double height;//高
    public MyRectangle(String color,double weight,double width,double height){
        super(color,weight);
        this.width = width;
        this.height = height;
    }

    @Override
    public double findArea(){
        return width * height;
    }
}

public class GeometricTest{
    public boolean equalsArea(GeometricPbject g1,GeometricPbject g2){
        return g1.findArea() == g2.findArea();
    }
    public void displayGeometricObject(GeometricObject g){//动态绑定
        System.out.println("几何图形的面积为:" + g.findArea());
    }

    public static void main(String[] args){
        GeometricTest test = new GeometricTest();
        Circle c1 = new Circle("red",1.0,2.3);
        Circle c1 = new Circle("red",1.0,3.3);

        test.displayGeometricObject(c1);
        test.displayGeometricObject(c2);
        boolean isEquals = test.equalsArea(c1,c2);
        if(isEquals){
            System.out.println("面积相等");
        }else{
            System.out.println("面积不等");
        }
    test.displayGeometricObject(new MyRectangle("blue",1.8,2.3))//使用匿名对象
    }
}

多态时编译时行为还是运行时行为?

编译时认为是声明类型,运行时才知道是new()的类型。所以是运行时的行为。

posted @ 2025-05-08 19:50  谁来着?  阅读(49)  评论(0)    收藏  举报