Java——多态

多态是同一个行为具有多个不同表现形式或形态的能力。

一、基本概念

多态就是同一个接口,使用不同的实例而执行不同操作,如图所示(来自菜鸟教程):
在这里插入图片描述
多态存在的三个必要条件

  • 继承
  • 子类要对父类方法进行重写
  • 通过父类引用指向子类对象,调用重写方法Parent P = new Child();

优点:

  • 消除类型之间的耦合关系
  • 可替换性
  • 可扩充性
  • 接口性
  • 灵活性
  • 简化性

二、多态的示例

通过示例来理解多态:

//Animal.java
public class Animal {
    String breed;
    String name;

    public Animal(String breed, String name) {
        this.breed = breed;
        this.name = name;
    }
	//父类的吃的方法
    public void eat(){
        System.out.println(name+"在吃饭ing");
    }
}
//Dog.java
public class Dog extends Animal {
    public Dog(String breed, String name) {
        super(breed, name);
    }
    //对吃的方法进行了重写
    public void eat(){
        System.out.println(name+"在吃骨头ing");
    }
}
//Cat.java
public class Cat extends Animal{
    public Cat(String breed, String name) {
        super(breed, name);
    }
    //对吃的方法进行了重写
    public void eat(){
        System.out.println(name+"在吃鱼ing");
    }
}
//Test.java
public class Test {
    public static void eat(Animal animal){
    	//编译器编译的时候并不知道要调用哪个类中的方法,该处的这种行为叫做多态
    	//只有当程序运行起来,编译器才能通过形参引用的具体对象,确定调用哪个类中的方法
    	//此处的形参必须是父类类型才行
        animal.eat(); 
    }
    public static void main(String[] args) {
        Cat cat = new Cat("英短","小灰");
        Dog dog = new Dog("拉布拉多","旺财");
        Animal animal = new Animal("动物","某动物");

        eat(cat);
        eat(dog);
        eat(animal);
    }
}

在这里插入图片描述

三、重写

重写(override): 也称为覆盖。重写是子类对父类非静态、非private修饰,非final修饰,非构造方法等的实现过程进行重新编写, 返回值和形参都不能改变,只改写其中的方法实现。重写的好处在于子类可以根据需要,定义特定于自己的行为。 也就是说子类能够根据需要实现父类的方法。

方法重写的规则:

  • 子类在重写父类方法时,一般情况下必须与父类方法原型一致,即:修饰符 返回值类型 方法名(参数列表)。
  • JDK7之后,重写的方法返回值可以不同,但必须具有父子关系。
  • 子类重写的方法访问权限不能比父类中被重写的方法访问权限更低。例如:如果父类方法被public修饰,则子类中重写该方法就不能声明为 protected
  • 父类中被staticprivate修饰的方法或者构造方法都不能被重写。
  • 子类和父类在同一个包中,那么子类可以重写父类的所有方法,除了被privatefinal修饰的方法。
  • 子类和父类不在同一个包中,那么子类只能够重写父类的声明为 publicprotected 的非 final 方法。
  • 可以使用 @Override 注解来显式指定。有了这个注解能帮我们进行一些合法性校验。
    示例:
	//父类中的方法
	public void eat(){
        System.out.println(name+"在吃饭");
    }
	//子类中重写的方法
    @Override
    private void eat(){
        System.out.println(name+"在吃骨头ing");
    }

在这里插入图片描述

1、重载和重写的区别

区别重载(Overload)重写(Override)
参数列表必须修改不能修改
返回类型可以修改不能修改
访问限定符可以修改不能做更严格的限定,但可以降低限定
异常可以修改可以减少或删除,一定不能抛出新的或者更广的异常

注: 方法重载是一个类的多态性表现;方法重写是子类与父类的一种多态性表现。

四、向上/下转型

1、向上转型

其实质就是创建一个子类对象,将其作为父类对象来使用。
语法格式:

父类类型 对象名 = new 子类类型()

示例:

 Animal animal = new Dog("中华田园犬","阿黄"); //因为狗都是动物

animal是父类类型,引用了一个子类对象,把子类对象当作父类对象来用。因为是从小范围到大范围的转换,所以向上转型是安全的。
使用的场景:

  • 直接赋值
  • 方法传参
  • 方法返回
public class Test {
    //方法传参:接受任意子类对象
    public static void eat(Animal animal){
        animal.eat();
    }

    //返回值:返回任意子类对象
    public static Animal buyAnimal(String need){
        if ("狗" == need)
            return new Dog("英短","小灰");
        else if ("猫" == need)
            return new Cat("中华田园犬","旺财");
        else
            return null;
    }

    public static void main(String[] args) {
        Animal cat = new Cat("狸花猫","小花"); //子类对象赋值给父类对象
        Dog dog = new Dog("雪纳瑞","大白");

        eat(cat);
        eat(dog);

        System.out.println("=======================");
        Animal animal = buyAnimal("猫");
        animal.eat();

        System.out.println("=======================");
        animal = buyAnimal("狗");
        animal.eat();
    }
}

在这里插入图片描述
向上转型缺点:不能调用到子类特有的方法

//
public class Cat extends Animal{
   public Cat(String breed, String name) {
        super(breed, name);
    }

	//Cat类特有的方法
   public void printCat() {
        System.out.println("Cat.toString");
    }
}
	Animal cat = new Cat("狸花猫","小花"); //子类对象赋值给父类对象
    cat.printCat(); //该部分会报错

在这里插入图片描述

2、向下转型

将一个子类对象先经过向上转型当作父类方法使用,再无法调用子类方法,但有些时候可能又需要调用子类中的特有方法,此时就需要向下转换,将父类引用还原为子类对象。(向下转型应用较少,因为不安全)
用动物类来举例可能出现两种情况:
在这里插入图片描述

    public static void main(String[] args) {
        Cat cat = new Cat("英短","小灰");
        Dog dog = new Dog("中华田园犬","旺财");

        //向上转型
        Animal animal = cat;
        animal.eat();
        animal = dog;
        animal.eat();

        cat = (Cat)animal; //可以通过编译,但是运行时会抛出异常
		
		//animal原本也是dog所以安全可以转换
        dog = (Dog)animal;
        dog.printDog();
    }

在这里插入图片描述
在这里插入图片描述

3、instanceof关键字提高向下转型的安全性

为了提高向下转型的安全性,引入instanceof关键字,如果表达式为true,则可安全转换。

    public static void main(String[] args) {
        Cat cat = new Cat("英短","小灰");
        Dog dog = new Dog("中华田园犬","旺财");

        //向上转型
        Animal animal = cat;
        animal.eat();
        animal = dog;
        animal.eat();
        
        if (animal instanceof Cat){
            cat = (Cat)animal; 
        }
        if (animal instanceof Dog) {
            dog = (Dog) animal;
            dog.printDog();
        }
    }
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值