java三大特性之多态

【基础最重要】

多态概述

在设计一个方法时,通常希望该方法具备一定的通用性。比如要实现一个动物叫的方法,肯定是想要根据不同的动物而发出应该的声音。因此可以在方法中接收一个动物类型的参数,这样就能能实现不同的动物发不同的叫声的目的。在同一个方法中,这种由于参数类型不同而导致执行效果各异的现象就是多态

在java中为了实现多态,允许使用一个父类类型的变量来引用一个子类类型的对象(向上转型),根据被引用子类对象特征的不同,得到不同的运行结果。

//定义接口animal
interface Animal{
 void shout(); //定义抽象方法shout()
}
//定义Cat类实现Animal接口
class Cat implements Animal{
//实现shout()方法
  public void shout(){
   System.out.println("喵喵~~"); 
  }
}
//定义Dog类实现Animal接口
class Dog implements Animal{
  //实现shout()方法
   public void shout(){
     System.out.println("旺旺...."); 
   }
}
//定义测试类
public class Test{
  public static void main(String[] args){
    Animal an1 = new Cat();//创建Cat对象,使用Animal类型的变量an1引用
    Animal an2 = new Dog();//创建Dog对象,使用Animal类型的变量an2引用
    animalShout(an1);//调用animalShout()方法,将an1作为参数传入
    animalShout(an2);//调用animalShout()方法,将an2作为参数传入

    //定义静态的animalShout()方法,接收一个Animal类型的参数
    public static void animalShout(Animal an){
       an.shout();//调用实际参数的shou()方法
    }
  }
}

执行以上代码,得到的结果是,猫类发出“喵喵~~”叫,狗类发出“旺旺….”叫,完美的实现了多态。

此处Animal是定义成接口,其实Animal是一个抽象类也是可以的。即Animal需是一个超类型。


在多态的学习中,涉及到子类对象当做父类类型使用的情况
Animal an1 = new Cat(); //将Cat对象当做Animal类型来使用
Animal an2 = new Dog(); //将Dog对象当做Animal类型来使用`

将子类对象当做父类使用时不需要任何显式地声明(此处为向上转型。ps:当向下转型时需要显式地声明,比如强制转换),但是需要注意的是,此时不能通过父类变量去调用子类中的某些方法(比如子类中自己定义的方法就不能调用)。

如果一定要用的话,可以向下转型从父类转型为子类(Cat cat = (Cat) animal),这样就可以调用子类中的方法。但是这样一来就失去了多态的灵活性了,因为当你传进来的是Dog类型,你就没法从Dog转型到Cat型了,运行时就会报错。针对这种情况,java提供了一个关键字instanceof,它可以判断一个对象是否为某个类(接口)的实例或者子类实例,语法格式如下:

对象(或者对象引用变量) instanceof 类(接口)

实际例子:

public static void animalShout(Animal animal){
   if(animal instanceof Cat){//判断animal是否是Cat类的实例对象
      Cat cat = (Cat)animal;//这里就是强制转换了,强行将animal转成Cat类型
      cat.eat();
      cat.shout();
   }else{
      //写其他的逻辑代码
   }
}

这里做一些补充:
常常有这种说法:“……子类实例化的动作不再需要在代码中硬编码,而是在运行时才指定具体实现的对象。”下面用几行代码来解释这句话,见下面代码:

public abstract class Duck{
   FlyBehavior flyBehavior;   //声明引用变量,鸭子会飞的行为

   public class performFly(){
      flyBehavior.fly();    //调用方法
   }
}

//继承Duck
public class Duck1 extends Duck{
   public Duck1(){
      flyBehavior = new FlyWithWings();
   }
}

//FlyBehavior接口
public interface FlyBehavior{
   public void fly();
}

//实现FlyBehavior接口
public class FlyWithWings implements FlyBehavior{
   public void fly(){
      System.out.println("I am flying!");
   }
}

//测试类
public class Test{
  public static void main(String[] args){
     Duck duck1 = new Duck1();
     duck1.performFly();
  }
}

代码解释:

  • 我们在超类中声明了一个抽象对象,并且在performFly()方法中调用了其中的fly()方法。这部分代码中,我们不在乎flyBehavior接口的对象到底是什么(因为我们还没有实例化它),我们只关心该对象知道如何飞就够了。
  • 子类Duck1继承Duck,就会继承flyBehavior这个属性,duck1.performFly()会调用Duck1继承而来的performFly()方法,进而委托给该对象(duck1)的FlyBehavior对象处理(也就是说,调用继承来的flyBehavior引用对象的fly()),并且在Duck1的默认构造函数中这么定义:flyBehavior = new FlyWithWings();所以最终怎么实现飞就是在这里执行的。
  • 1
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值