Java——多态

1.多态概述

多态是面向对象语言三大特征之一,多态是指对象的多种形态,就是同类型的对象,表现出的不同形态。

多态的前提:有继承关系,有父类引用指向子类对象,有方法重写

多态的表现形式:父类类型 对象名称=子类对象;

1.1多态的场景应用

在一个球类信息管理系统当中,我们要去写一个方法查看各种各样球的信息

是每一种球都写一种方法查看信息呢?还是只写一种方法去查看所有的球的信息好呢?

答案肯定是只写一种

接下来简单的实现一个球类信息查看的系统

class Ball{
    private int price;
    public int getPrice() {
        return price;
    }
    public void setPrice(int price) {
        this.price = price;
    }
    public void show(){
    }
}

class pingpong extends Ball{
    public void show(){
        System.out.println("乒乓球的价格为"+getPrice()+"元");
    }
}
class badminton extends Ball{
    public void show(){
        System.out.println("羽毛球的价格为"+getPrice()+"元");
    }
}
class basketball extends Ball{
    public void show(){
        System.out.println("篮球的价格为"+getPrice()+"元");
    }
}
class football extends Ball{
    public void show(){
        System.out.println("足球的价格为"+getPrice()+"元");
    }
}
public class T2 {
    public static void main(String[] args) {
        Ball b1=new pingpong();
        b1.setPrice(2);
        show(b1);
        Ball b2=new badminton();
        b2.setPrice(4);
        show(b2);
    }
    public static void show(Ball p){
       p.show();
    }
}

当我们将乒乓球和羽毛球的对象赋值给父类的对象时,将父类类型作为查看信息的方法的形参,用父类类型的变量调用show方法时,会发现父类类型的变量会调用不同子类的show方法,这就是多态的一种应用场景

2.多态调用成员的特点

1.变量调用:编译看左边,运行也看左边

2.方法调用:编译看左边,运行看右边

2.1变量调用

class Animal{
}

class Dog extends Animal{
    String name;
}
public class T3 {
    public static void main(String[] args) {
        Animal ani=new Dog();
ani.name="张三";
    }
}

编译看左边:javac编译代码的时候会看左边的父类里面有没有这个变量,如果有,则成功编译,否则编译失败。上面代码因为父类里面没有name这个变量,所以会编译失败

class Animal{
    String name="动物";
}
class Dog extends Animal{
    String name="狗";
}
public class T3 {
    public static void main(String[] args) {
        Animal ani=new Dog();
        System.out.println(ani.name);
    }
}

运行也看左边:我们分别给父类和子类的name赋不同值时,在用ani调用name时,输出的结果是动物,也就是运行时ani调用的是父类的name

2.2方法调用

class Animal{
}
class Dog extends Animal{
   public void show(){
       System.out.println("Dog的show");
   }
}
public class T3 {
    public static void main(String[] args) {
        Animal ani=new Dog();
        ani.show();
    }
}

编译看左边:和变量调用一样,ani调用show方法时,父类里面有show,则编译成功,没有则编译失败

class Animal{
    public void show(){
        System.out.println("Animal的show");
    }
}
class Dog extends Animal{
   public void show(){
       System.out.println("Dog的show");
   }
}
public class T3 {
    public static void main(String[] args) {
        Animal ani=new Dog();
        ani.show();
    }
}

运行看右边:Animal和Dog类里面都有show方法时,我们使用ani调用show方法时,ani会调用子类Dog里面的show方法

2.3对方法调用和变量调用的理解

成员变量:

在子类的对象中,会把父类的成员变量继承下来

当我们Animal a=new Dog();时,父类里面有一个name,子类里面也有一个name,这两个name在对象里面都是存在的

之前我们用Dog dog=new Dog()创建一个对象时,用dog调用name,dog是Dog类型,他会去Dog类里面寻找name,现在用Animal a=new Dog();创建a对象,a是Animal类型,a调用name,那么他就会去Animal里面去寻找name

成员方法:

当我们运用多态去调用方法时,子类里面的方法其实是对父类方法的重写,而子类继承父类方法时继承父类的虚方法表,当子类对父类方法进行重写时,会将父类方法在虚方法表中的虚方法覆盖,从而在用ani.show时,调用的是子类的方法

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

 1.测试类的字节码文件T3.class先加载到方法区当中,java虚拟机会自动的将main方法加载进栈

2.在main方法的第一行代码,即用到了Animal类又用到了Dog类,在Java中,永远是先加载父类,再加载子类,Java中有一个所有类的祖宗类(object类),这里object没太大关系,所以在图中就不画了,在方法区中先加载Animal.class,再加载Dog.class。

(在字节码文件中会加载所有的成员变量和成员方法,在成员方法的下面会挂一个需方法表,子类的重写方法会将继承下来的虚方法表中父类show方法的虚方法覆盖)

(子类会和父类有联系,他会记录父类字节码文件的位置)

3.第一行代码等号的左边会在栈内存里面开辟一个Animal类型,名为ani的空间,等号右边,new关键字代表在堆内存里面开辟了一个小空间,在对象里面,他会将这个空间分为两部分,一部分用来存储在父类继承下来的成员信息,另一部分会存储自己的成员信息,假设这块堆内存的地址值为1900,栈内存里面ani的空间会存储1900这个地址值,ani可以通过1900找到堆内存里面的变量

4.第二行代码sout(ani.name),这时就编译看左边,运行也看左边,看1900里面父类是否有name,有就编译成功,否则失败,ani是Animal类型的,他直接去父类里面调用name

5.第三行代码,编译看左边,运行看右边,编译时他会去看父类里面有没有show,有则编译成功,否则编译失败。在运行时他会去子类里面找show方法,因为子类重新将需方法表中的show方法覆盖,所以调用的是子类的show方法

3.多态的优势和弊端

优势:

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

举例:

Animal a=new Dog();
a.eat;

当我后面想要Cat的eat时,只需将new Dog()改成new Cat(),就可完成业务逻辑的修改,无需将后续的代码修改

2.定义方法的时候,使用父类类型作为参数,可以接收所有的子类对象,体现多态的扩展性和便利

弊端:

1.不能调用子类的特有方法

解决方案:强制转换,将调用者变回子类类型,转换时不能瞎转,即Animal dog=new Dog();不能将dog转成Cat类型,瞎转会报类型转换异常

补充:instanceof关键字

instanceof关键字是判断某一个对象是不是某个类型

格式

对象名 instanceof 类名

如果这个对象的类型是后面那个类,那么整个结果是true 否则是false

  • 59
    点赞
  • 48
    收藏
    觉得还不错? 一键收藏
  • 38
    评论
评论 38
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值