【JAVA基础】多态


多态

父类的引用指向子类的对象

public class A {
    public String name;
    public int age;

    public void run(){ //该run()方法被覆盖
        System.out.println("a跑的快");
    }

    public void eat(String name){
        System.out.println(name+"吃的很多");
    }
}

public class B extends A{
    public char sex;
    public double height;

    public void fly(){
        System.out.println("b飞的很高");
    }

    @Override
    public void run(){
        System.out.println("b跑的快");
    }
}

public class Test {
    public static void main(String[] args) {
        A ab = new B();  // 数据类型:决定在内存中的存储形式 ab是A类数据类型
                         // 创建子类对象前提一定会创建父类对象,此时在内存中A和B的对象都存在
        ab.name = "李四";
        ab.age = 18;
        ab.eat("张三");
        ab.run();
    }
}

以上代码中对象ab就是多态,其中:

  1. 因为ab为A类的数据类型,以A类为模板,所以他可以调用到A类中的属性

  2. ab为B类的对象,而B为A的子类,那么创建子类对象之前一定会先创建父类对象,所以ab可以访问A类中的方法

  3. 但是ab实际上指向的是子类对象的内存空间,因为受限于父类数据类型,所以只能对父类中的数据进行访问,子类中单独的数据并不能够进行访问

在这里插入图片描述

  1. ab满足了定义父类引用指向子类对象

我们看一下内存图:

创建对象ab的过程如下:

  1. ab属于B类对象,但是B类拥有A父类,那么创建子类对象之前先创建父类对象,为A类对象开辟空间,在其中存储name、age两个变量和run()、eat()两个方法
  2. 再为B类对象,其中包括sex、height两个变量和run()、fly()
  3. 因为B类为A类的子类,所以run()方法被重写,ab对象访问的话只能访问到B类中的run()方法和A中的eat()方法
  4. 因为ab为A类的数据类型,以A类为模板,所以他可以调用到A类中的属性
    在这里插入图片描述

向上转型

public class C {
    public static void hanlder(A a){
        System.out.println("C的输出");
    }
}

public class Test {
    public static void main(String[] args) {
        B b = new B();
        C.hanlder(b); // 没有报错,为什么?
    }
}

在程序中,C类中的静态方法hanlder(A a)需要的参数为一个A类对象,但是在Test类中的main()方法里,我们却向方法传了一个B类的对象,编译器并没有报错,这是因为多态可以向上转型:子类的对象可以被父类所接受,也就是我们一开始说的定义:父类引用指向子类对象

练习题

A类

public class A {
    public String Show(D obj){
        return "A and D";
    }
    public String Show(A obj){
        return "A and A";
    }
}

B类

public class B extends A{
    public String Show(Object obj){
        return "B and B";
    }
    public String Show(A obj){
        return "B and A";
    }
}

C类

public class C extends B{
}

D类

public class D extends B{
}

Test类

public class Test {
    public static void main(String[] args) {
        A a1 = new A();
        A a2 = new B();
        B b  = new B();
        C c  = new C();
        D d  = new D();

        System.out.println(a1.Show(b)); // A and A
        System.out.println(a1.Show(c)); // A and A
        System.out.println(a1.Show(d)); // A and D

        System.out.println(a2.Show(b)); // B and A
        System.out.println(a2.Show(c)); // B and A
        System.out.println(a2.Show(d)); // A and D

        System.out.println(b.Show(b)); // B and A
        System.out.println(b.Show(c)); // B and A
        System.out.println(b.Show(d)); // A and D
    }
}

我们来逐个分析一下:

首先我们可以看到A类的优先级最高,是其他BCD类的父类,B类直接继承A类,CD类直接继承B类。

  • 那么对于对象a1

    它属于A类对象,创建时只开辟A类对象的内存空间,可以调用A类中的两种Show()方法,虽然B类中有对Show方法重写,但是此时并没有开辟B类对象的内存空间,所以并不会出现重写覆盖的现象

    System.out.println(a1.Show(b)); // A and A
    

    a1为A类对象,只能访问A类中的数据,b属于B类对象,B类为A的子类,所以向上转型,可以被A中的show(A obj)方法接受

    System.out.println(a1.Show(c)); // A and A
    

    同理,c为C类对象,拥有B父类,B父类拥有A父类,所以和第一个同理

    System.out.println(a1.Show(d)); // A and D
    

    虽然也是通过a1访问,但是传入的参数为d,show()方法的重载,选择第一个show(D obj)方法

    在这里插入图片描述

  • 对于对象a2

    它属于A类数据类型的B类对象,也就是多态,创建时B类为A类的子类,创建子类对象之前要创建父类对象,所以会为A类、B类对象都开辟内存空间。因为a2的数据类型为A类数据类型,所以只能访问A类中的数据,但是同时开辟了B类的内存空间,所以B类中如果有对A类方法的重写,则调用B中的重写方法

    System.out.println(a2.Show(b)); // B and A
    

    a2为数据类型为A的B类对象,创建子类对象时先创建父类对象,创建时分别为A类、B类开辟空间,然后因为是A类数据类型,所以应该访问A类中的show(A obj)方法,但是因为中对方法有重写,所以访问B类中的show(A obj)

    System.out.println(a2.Show(c)); // B and A
    

    同理,c为C类对象,但是向上转型,可以被show(A obj)接受

    System.out.println(a2.Show(d)); // A and D
    

    同理,但是传入的参数为d,由于方法重载,所以访问show(D obj)

    在这里插入图片描述

  • 对于对象b

    它属于B类对象,B类是A类的子类,创建子类对象之前先创建父类对象,所以在创建对象b时,会先为A类对象开辟内存空间,再开辟B类对象空间。对象b可以访问A类和B类中的方法,如果B类中存在方法重写,那么访问B类中的重写方法

    System.out.println(b.Show(b)); // B and A
    

    b为B类对象,访问B类中的Show(A obj),这里存在向上转型的情况,从下往上匹配,Object类属于所有类的父类,所以先匹配A类参数,所以访问Show(A obj)

    System.out.println(b.Show(c)); // B and A
    

    b为B类对象,传入c对象,由于方法重写以及向上转型访问B类中的show(A obj)

    System.out.println(b.Show(d)); // A and D
    

    b为B类对象,创建子类对象时先创建父类对象,访问A类中的show(D obj)

    在这里插入图片描述

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值