一、如何理解多态性:理解为一个事物的多种形态。

二、Java中多态性的体现:
    父类的引用指向子类的对象。(或子类的对象赋给父类引用)
    比如:Person p2 = new Man();

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

public class Person
{
    String name;
    int age;

    public void eat()
    {
        System.out.println("吃饭");
    }
    public void sleep()
    {
        System.out.println("睡觉");
    }
}
public class Man extends Person
{
    boolean isSmoking;

    public void eat()
    {
        System.out.println("男人吃肉长肌肉");
    }
    public void earnMoney()
    {
        System.out.println("挣钱养家");
    }
}
public class Woman extends Person
{
    boolean isBeauty;

    public void eat()
    {
        System.out.println("女人少吃减肥");
    }
    public void goShopping()
    {
        System.out.println("逛街购物");
    }

}
public class PersonTest
{
    public static void main(String[] args)
    {
        //一般的用法
        Person p1 = new Person();
        Man m1 = new Man();

        //多态性
        Person p2 = new Man();

        /*
        多态性的应用:虚拟方法调用
        在多态的场景下,调用方法时:
            编译时,认为方法是左边声明的父类的方法(即被重写的方法)
            执行时,实际执行的是子类重写父类的方法
        简称为:编译看左边,运行看右边
         */
        p2.eat();

        /*
        多态的弊端?
        问题:Person p2 = new Man();
            针对创建的对象,在内存中是否加载了Man类中声明的属性和方法?加载了
        问题:能不能直接调用Man中加载的属性和方法?不能
        */

    }
}
public class PersonTest1
{
    public static void main(String[] args)
    {
        Person p1 = new Man();
        //不能直接调用子类特有的结构
//        p1.earnMoney();
//        System.out.println(p1.isSmoking);

        //向下转型(使用强转符)
        Man m1 = (Man) p1;
        m1.earnMoney();
        System.out.println(m1.isSmoking);

        //p1和m1指向了堆空间中同一个对象
        System.out.println(p1 == m1);//true

        //向下转型可能会出现:数据类型转换异常
        Person p2 = new Woman();
//        Man m2 = (Man)p2;
//        m2.earnMoney();

        //使用instanceof进行判断,避免出现类型转换异常
        //a instanceof A:判断对象a是否是类A的实例。
        if(p2 instanceof Man)
        {
            Man m2 = (Man)p2;
            m2.earnMoney();
        }
        if(p2 instanceof Woman)
        {
            System.out.println("Woman");
        }
    }
}

四、多态性使用前提:
    ①要有类的继承关系
    ②要有方法的重写

五、多态的适用性:适用于方法,不适用于属性

六、多态的利弊:
好处:极大的减少了代码的冗余,不需要定义多个重载的方法。
    开发中:
        使用父类做方法的形参,是多态使用最多的场合。即使增加了新的父类,方法也无需改变,提高了扩展性,符合开闭原则。
    【开闭原则OCP】
        -对扩展开放,对修改关闭
        -通俗解释:软件系统中各种组件,如模块(Modules)、类(Classes)以及功能(Functions)等,应该在不修改现有代码的基础上,引入新的功能。
弊端:多态创建的对象不能直接调用子类的方法和属性

七、向上转型与向下转型:
    首先,一个对象在new的时候创建是哪个类型的对象,它从头至尾都不会变。即这个对象的运行时的类型,本质的类型不会变。但是,把这个对象赋值给不同的类型变量时,这些变量的编译时的类型却不同。

类型转换图例


    类型转换:
        因为多态,就一定会有把子类对象赋值给父类变量的时候,这个时候,在编译期间,就会出现类型转换的现象。
        但是,使用父类变量接收了子类对象之后,我们就不能调用子类独有的方法,所以想要调用子类特有的方法,就必须类型转换。
    向上转型:即多态
    向下转型:类似于强制类型转换,将父类对象转换为子类对象,使得新对象可以调用子类特有的属性和方法。
            但是向下转型的对象必须是所要转换类的实例,否则就会出现类型转换异常
    instanceof:可用来判断对象是否为某个类的实例

public class Animal
{
    private String name;
    private int age;

    public Animal(String name, int age)
    {
        this.name = name;
        this.age = age;
    }

    public void eat()
    {
        System.out.println("吃东西");
    }

    public int getAge()
    {
        return age;
    }
    public void setAge(int age)
    {
        this.age = age;
    }
    public String getName()
    {
        return name;
    }
    public void setName(String name)
    {
        this.name = name;
    }
}
public class Dog extends Animal
{
    public Dog(String name, int age)
    {
        super(name, age);
    }

    public void seeHome()
    {
        System.out.println("狗会看家");
    }
}
public class Cat extends Animal
{
    public Cat(String name, int age)
    {
        super(name, age);
    }

    public void eatMouse()
    {
        System.out.println("猫吃老鼠");
    }
}
public class Test
{
    public static void main(String[] args)
    {
        Animal a1 = new Animal("动物",10);
        Animal a2 = new Dog("狗",1);
        Animal a3 = new Cat("猫",1);

        Dog d1 = new Dog("狗",2);
        Cat c1 = new Cat("猫",2);
        System.out.println(a1 instanceof Animal);//true
        System.out.println(a1 instanceof Dog);//false
        System.out.println(a2 instanceof Animal);//true
        System.out.println(a2 instanceof Dog);//true
        System.out.println(a2 instanceof Cat);//false
        System.out.println(d1 instanceof Dog);//true
        System.out.println(d1 instanceof Animal);//true


        a2.eat();
        Dog d2 = (Dog)a2;
        d2.seeHome();
    }
}

Logo

Agent 垂直技术社区,欢迎活跃、内容共建。

更多推荐