Java学习笔记——多态(实例详解)

多态是某一事物,在不同时刻体现出来的不同的状态

就比如猫,狗,狼都是动物,我们可以说猫是动物,说狗是动物
但我们不能说动物是猫,动物是狼。也不能说猫是狗,或者狗是狼。
上面这几点都会在多态中体现出来

多态的前提:

  1. 类之间要有继承的关系
  2. 子类要有对父类方法的重写(不重写也不会报错,但这样体现不出来多态的意义)
  3. 父类的引用变量指向子类对象

下面看一个多态的简单例子

class Animal{
    public void eat(){
        System.out.println("动物要进食");
    }
}

class Cat extends Animal{
    public void eat(){
        System.out.println("猫咪要吃饭");
    }
}

public class Demo1 {
    public static void main(String[] args) {
        //从右往左念,猫咪是动物
        //new Cat()已经创建了一个Cat类的对象,在堆内存之中
        //Animal类的引用变量指向了Cat类的子类对象
        Animal a = new Cat();
        //这里会优先调用子类的重写方法
        a.eat();
    }
}

结果为
在这里插入图片描述
这里需要注意的是,虽然是父类的引用变量,但实际上调用eat()方法时,调用的是子类重写后的eat()方法

如果对重写不了解的话,可以看下面链接里面的博客
继承里面的重写问题

多态访问成员特点
1、成员变量
编译看左边,运行看左边
2、构造方法
创建子类对象的时候,先访问父类的构造方法,先对父类的数据进行初始化
3、成员方法
编译看左边,运行看右边
因为子类的成员方法存在重写,所以运行访问的时候看右边
4、静态的成员方法:
编译看左边,运行看左边
静态的随着类的加载而加载
由于被static修饰的都是与类有关系的,所以它算不上重写
所以,编译的时候看左边,运行访问的时候也看左边

这里的左边指的是父类的引用变量,右边指的是子类的对象
在这里插入图片描述
这个单独看文字比较难懂,所以下面还是要看几个例子
首先是第一条,成员变量,编译看左边,运行看左边

class Animal{
    int num =10;
    public void eat(){
        System.out.println("动物要进食");
    }
}

class Cat extends Animal{
    int num = 20;
    public void eat(){
        System.out.println("猫咪要吃饭");
    }
}

public class Demo1 {
    public static void main(String[] args) {
        Animal a = new Cat();
        System.out.println(a.num);
    }
}

输出结果为 10
编译和运行都看左边的意思是,输出的结果根据父类的属性值来定,而不是子类

然后是第二条,可以看这篇博客的后半部分,关于构造方法调用顺序的详细解释
关于构造方法调用顺序的详细解释

第三条成员方法,编译看左边,运行看右边

package test1;
class Father1{
    public Father1() {
    }
    public void show(){
        System.out.println("父类的show方法");
    }
}

class Son1 extends Father1{
    public Son1() {
    }
    public void show(){
        System.out.println("子类的show方法");
    }
}
public class duotaiDemo3 {
    public static void main(String[] args) {
        Father1 f = new Son1();
        f.show();
    }
}

结果为
在这里插入图片描述
而当子类没有重写这个方法时,会从父类中继承该方法,然后调用该方法

package test1;
class Father1{
    public Father1() {
    }
    public void show(){
        System.out.println("父类的show方法");
    }
}

class Son1 extends Father1{
    public Son1() {
    }
//    public void show(){
//        System.out.println("子类的show方法");
//    }
}
public class duotaiDemo3 {
    public static void main(String[] args) {
        Father1 f = new Son1();
        f.show();
    }
}

在这里插入图片描述

编译看左边的意思是编译过程中看父类中是否有这个方法
运行看右边的意思是运行过程中实际调用的方法是子类中重写后的方法

第四条静态的成员方法

package review;
class Animal{
    int num =10;
    public void eat(){
        System.out.println("动物要进食");
    }
    public static void sleep(){
        System.out.println("动物要休息");
    }
}

class Cat extends Animal{
    int num = 20;
    public void eat(){
        System.out.println("猫咪要吃饭");
    }
    public static void sleep(){
        System.out.println("猫咪要睡觉");
    }
}

public class duotaiDemo {
    public static void main(String[] args) {
        Animal a = new Cat();
        a.sleep();

        System.out.println("------------");
        Animal.sleep();
        Cat.sleep();
    }
}

结果为
在这里插入图片描述
用对象调用时,调用的是父类的静态成员方法
用类名调用时,都是打印相对应的结果

介绍完多态访问成员的特点后,我们需要思考一个问题,为什么要使用,以及使用多态有什么好处
下面来看这个例子

class Animal{
    public void eat(){
        System.out.println("动物要进食");
    }
    public void sleep(){
        System.out.println("动物要休息");
    }
}

class Cat extends Animal{
    public void eat(){
        System.out.println("猫咪要吃饭");
    }
    public void sleep(){
        System.out.println("猫咪要睡觉");
    }
}

class Dog extends Animal{
    public void eat(){
        System.out.println("狗要啃骨头");
    }
    public void sleep(){
        System.out.println("狗要打盹");
    }
}

public class Demo1 {
    public static void main(String[] args) {
        Cat c = new Cat();
        c.eat();
        c.sleep();
        Dog d = new Dog();
        d.eat();
        d.sleep();
    }
}

这里发现,如果输出猫和狗的实例对象的eat和sleep方法的结果,就需要分别用Cat类的对象c来调用,用Dog类的对象d来调用。这里是因为对象较少,调用的方法也只有eat和sleep两个方法,所以看起来还算简洁。

但如果我要创建十只猫的实例呢?要c1.eat(),c2.sleep()……这样一直调用下去吗?
那如果我不止猫和狗两种动物呢?我还要写狼的类,写豹子的类,写大象的类,都继承Animal类,然后输出这些类的对象调用方法的结果。

这时就会发现,代码的调用方法部分将变得非常冗长,有没有一种办法,可以让我们不需要用实例对象一个一个的调用方法呢?
这时候我们就需要用到多态了。而我们需要做的事情,就是创建对象,并且将对象作为参数传入一个工具类中,工具类里面会定义各种需要调用的方法。

class Animal{
    public void eat(){
        System.out.println("动物要进食");
    }
    public void sleep(){
        System.out.println("动物要休息");
    }
}

class Cat extends Animal{
    public void eat(){
        System.out.println("猫咪要吃饭");
    }
    public void sleep(){
        System.out.println("猫咪要睡觉");
    }
}

class Dog extends Animal{
    public void eat(){
        System.out.println("狗要啃骨头");
    }
    public void sleep(){
        System.out.println("狗要打盹");
    }
}

class Bird extends Animal{
    public void eat(){
        System.out.println("鸟儿吃虫子");
    }
    public void sleep(){
        System.out.println("鸟儿休憩");
    }
}
class AnimalTools {
//private的作用是让外面无法创建AnimalTools类的对象,只能使用这里面的方法
    private AnimalTools() {
    }
    public static void funAnimal(Animal animal){
        animal.eat();
        animal.sleep();
    }
}
public class Demo1 {
    public static void main(String[] args) {
        Cat c = new Cat();
        Dog d = new Dog();
        Bird b = new Bird();
        AnimalTools.funAnimal(c);
        AnimalTools.funAnimal(d);
        AnimalTools.funAnimal(b);
        Cat c2 = new Cat();
        AnimalTools.funAnimal(c2);
    }
}

结果为
在这里插入图片描述

多态的好处:
提高了程序的维护性(由继承保证)
提高了程序的扩展性(由多态保证)

  • 30
    点赞
  • 120
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

一纸春秋

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值