Java的多态

Java的多态

​ 同种类型的对象,表现出的不同的形态

一、多态的表现形式

  • 父类类型 对象名称 = 子类对象;

二、多态的前提

  • 有继承/实现关系
  • 有父类引用指向子类对象
  • 有方法的重写

好处:使用父类型作为参数,可以接收所有的子类对象,体现多态的扩展性与便利

三、多态调用成员的特点

  • 变量调用 :++编译看左边,运行也看左边++
  • 方法调用 :++编译看左边,运行看右边++

多态调用成员的内存图解:

  1. 测试类Test的字节码文件先加载到方法区中,虚拟机会自动的调用main方法加载到栈
  2. 第一行代码,用到了两个类,那必定是先加载父类的字节码文件 此处应该还有Object类的字节码文件,但是此处用不到,就省略了,所以先加载Animal类的字节码文件,并挂上++虚方法表++ ;接下来加载Dog类的字节码文件,与此同时会把父类的虚方法表继承下来,并把show方法进行一个覆盖,并建立联系(Dog类会记录自己的父类Animal类字节码文件的位置)
  3. 第一行代码,左边Animal a会在栈区开辟一个小空间,右边遇见new关键字,会在堆区开辟一个空间,一部分存储从父类继承下来的成员变量的信息,另一部分则存储自己的成员变量的信息,赋值并将地址值传给栈区的变量a的空间中
  4. 第二行代码,用多态方法调用成员变量,(编译看左边)虚拟机会先看栈区空间的父类区域,若有该成员变量,则编译成功,否则编译失败,(运行也看左边)且运行也会直接看父类空间中的name的值,并获取打印出来【若没有使用多态创建对象,调用对象会首先在子类区域寻找,没有才会从父类中寻找
  5. 第三行代码,用多态方式调用成员方法,(编译看左边)在编译的时候会先去找父类里面有没有show方法,如果没在父类中没找到则会报错,(运行看右边)在实际运行时看的是子类的show方法(虚方法表中),所以子类的show方法会被加载进栈,并运行
示例代码
java 复制代码
public class Test {
    public static void main(String[] args) {
        // 创建对象(多态方式)
        Animal a = new Dog();

        // 调用成员变量时:编译看左边,运行也看左边
        // 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个变量,如果有,编译成功,如果没有编译失败
        // 运行也看左边:java运行代码的时候,实际获取的就是左边父类中成员变量的值
        System.out.println(a.name); // 动物

        // 调用成员方法:编译看左边,运行看右边
        // 编译看左边:javac编译代码的时候,会看左边的父类中有没有这个方法,如果有,编译成功,如果没有则编译失败
        // 运行看右边;java运行代码的时候,实际上运行的是子类中的方法
        a.show();   // Dog------show方法

        // 成员变量:a是Animal类型的,所以默认都会从Animal这个类中去找
        // 成员方法:如果子类对方法进行了重写,那么在虚方法表中是会把父类中的方法进行覆盖的
    }
}

class Animal {
    String name = "动物";

    public void show() {
        System.out.println("Animal------show方法");
    }
}

class Cat extends Animal{
    String name = "小猫";
    @Override
    public void show() {
        System.out.println("Cat------show方法");
    }
}

class Dog extends Animal{
    String name = "小狗";

    @Override
    public void show() {

        System.out.println("Dog------show方法");
    }
}

四、多态的优势和弊端

优势:

  • 方法中,使用父类型作为参数,可以接收所有子类对象

  • 在多态形式下,右边对象可以实现解耦合,便于扩展和维护

java 复制代码
Person p = new Student ();
p.work(); // 业务逻辑发生改变时,后序代码无需修改
  • 定义方法时,使用父类型作为参数,可以接收所有子类对象,体现多态的扩展性与便利

弊端:

  • 不能使用子类的特有功能

若要使用子类的特有功能则必须进行类型转换

引用数据类型的类型转换:
  • 自动类型转换:(低转高)
java 复制代码
Animal a = new Dog();
  • 强制类型转换:(高转低)
java 复制代码
Dog b = (Dog)a;

进行强制类型转化时,可以使用instanceof关键字来判断和转换(如下示例代码中)

强制类型转换能解决的问题
  • 可以转换成真正的子类类型,从而调用子类独有的功能
  • 转换类型与真实对象类型不一致会报错
  • 转换的时候用instanceof关键字进行判断

示例代码:

java 复制代码
public class Test {
    public static void main(String[] args) {
        // 自动类型转化
        Animal a = new Dog();
        a.eat();	// 输出: 狗吃骨头

        // 多态的弊端
        // a.lookhome()不能调用子类的特有功能
        // 因为在多态中方法的调用是编译看左边------------而左边父类中没有子类的特有方法,导致编译失败
        // 若要实现只能通过强制类型转化(但转化的类型必须对应好)

        Dog b = (Dog)a;
        b.lookhome();	// 输出: 狗在看家
        // 可以通过instanceof判断类型在进行强转
        if (a instanceof Dog) {
            Dog c = (Dog)a;
            c.lookhome();	// 输出: 狗在看家
        }else if (a instanceof Cat) {
            Cat c = (Cat)a;
            c.catchmouse();	// 输出: 狗在看家
        }else {
            System.out.println("没有此类型,无法转换");
        }
        // JDK14之后instanceof出了更简洁的方法
        if (a instanceof Dog d) {
            d.lookhome();
        }else if (a instanceof Cat d) {
            d.catchmouse();
        }else {
            System.out.println("没有这个类型,无法转换");
        }
    }
}

class Animal {
    public void eat() {
        System.out.println("动物在吃东西");
    }
}

class Dog extends Animal {
    @Override
    public void eat() {
        System.out.println("狗吃骨头");
    }

    public void lookhome() {
        System.out.println("狗在看家");
    }
}

class Cat extends Animal {
    @Override
    public void eat() {
        System.out.println("猫在吃小鱼干");
    }

    public void catchmouse() {
        System.out.println("猫正在抓老鼠");
    }
}

五、综合练习:

Animal类:

java 复制代码
public class Animal {
    private int age;
    private String color;

    public Animal() {

    }

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

    public void setAge(int age) {
        this.age = age;
    }

    public int getAge() {
        return age;
    }

    public void setColor(String color) {
        this.color = color;
    }

    public String getColor() {
        return color;
    }

    public void eat(String something) {
        System.out.println("动物在吃" + something);
    }

}

Person类:

java 复制代码
public class Person {
    private String name;
    private int age;

    public Person() {

    }

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

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public void keepPet(Animal an, String something) {
        if(an instanceof Dog d) {
            System.out.println("年龄为" + age + "岁的" + name + "养了一只" + an.getColor() + "的" + an.getAge() + "岁的狗");
            d.eat("骨头");
            d.lookhome();
        } else if (an instanceof Cat c) {
            System.out.println("年龄为" + age + "岁的" + name + "养了一只" + an.getColor() + "的" + an.getAge() + "岁的猫");
            c.eat("鱼");
            c.catchMouse();
        } else {
            System.out.println("没有这种动物");
        }
    }
}

Dog类:

java 复制代码
public class Dog extends Animal{
    public Dog() {

    }
    public Dog(int age, String color) {
        super(age, color);
    }
    public void lookhome() {
        System.out.println("狗在看家");
    }

    public void eat(String something) {
        System.out.println(getAge() + "岁的" + getColor() + "的狗两只前腿死死的抱住" + something + "猛吃");
    }
}

Cat类:

java 复制代码
public class Cat extends Animal{
    public Cat() {

    }
    public Cat(int age, String color) {
        super(age, color);
    }
    public void catchMouse() {
        System.out.println("猫在逮老鼠");
    }
    public void eat(String something) {
        System.out.println(getAge() + "岁的" + getColor() + "的猫眯着眼睛侧着头吃" + something);
    }
}

测试类:

java 复制代码
public class Test {
    public static void main(String[] args) {
        Person p1 = new Person("老王", 30);
        Dog d = new Dog(2, "黑颜色");
        p1.keepPet(d, "骨头");

        Person p2 = new Person("老李", 25);
        Cat c = new Cat(3, "灰颜色");
        p2.keepPet(c, "鱼");

    }
}

运行结果:

相关推荐
ajsbxi1 分钟前
苍穹外卖学习记录
java·笔记·后端·学习·nginx·spring·servlet
&岁月不待人&16 分钟前
Kotlin by lazy和lateinit的使用及区别
android·开发语言·kotlin
StayInLove20 分钟前
G1垃圾回收器日志详解
java·开发语言
对许24 分钟前
SLF4J: Failed to load class “org.slf4j.impl.StaticLoggerBinder“
java·log4j
无尽的大道28 分钟前
Java字符串深度解析:String的实现、常量池与性能优化
java·开发语言·性能优化
爱吃生蚝的于勒31 分钟前
深入学习指针(5)!!!!!!!!!!!!!!!
c语言·开发语言·数据结构·学习·计算机网络·算法
小鑫记得努力37 分钟前
Java类和对象(下篇)
java
binishuaio40 分钟前
Java 第11天 (git版本控制器基础用法)
java·开发语言·git
zz.YE42 分钟前
【Java SE】StringBuffer
java·开发语言
老友@42 分钟前
aspose如何获取PPT放映页“切换”的“持续时间”值
java·powerpoint·aspose