大数据——Java三大特征之一多态

实现多态

Java面相对象还有个重要的特征:多态。

认识多态

多态一词的通常含义是指能够呈现出多种不同的形式或形态。而在程序设计的术语中,它意味着一个特定类型的变量可以引用不同类型的对象,并且能自动地调用引用的对象的方法,也就是说根据作用到的不同对象类型,响应不同的操作。方法重写是实现多态的基础。
示例一:
有一个宠物类Pet,它有几个子类,如Bird(小鸟)、Dog(狗)等,其中宠物类定义了看病的方法toHospital(),子类分别重写了看病的方法。请在main()方法中分别实例化各种具体的宠物,并调用看病的方法。
关键代码:

//Pet父类
public class Pet {
    public void toHospital(){
        System.out.println("宠物看病!");
    }
}
//Dog子类继承Pet父类
public class Dog extends Pet {
    public void toHospital(){
        System.out.println("狗狗看病!");
    }
}
//Bird子类继承Pet父类
public class Bird extends Pet{
    public void toHospital(){
        System.out.println("小鸟看病!");
    }
}
//以上为Pet和其子类代码,以下为调用代码
public class Test {
    public static void main(String[] args) {
        Dog dog=new Dog();
        dog.toHospital();//狗狗看病
        Bird bird=new Bird();
        bird.toHospital();//小鸟看病
    }
}

输出结果:
在这里插入图片描述
也可以用示例一的代码实现相同的功能。
示例二:

//以上为Pet和其子类代码,以下为调用代码
public class Test {
    public static void main(String[] args) {
      /*  Dog dog=new Dog();
        dog.toHospital();//狗狗看病
        Bird bird=new Bird();
        bird.toHospital();//小鸟看病*/
      Pet pet;
      pet=new Dog();
      pet.toHospital();//狗狗看病
      pet=new Bird();
      pet.toHospital();//小鸟看病
    }
}

输出结果:
在这里插入图片描述
示例二和实例一中两端Test类的代码运行效果完全一样。虽然示例二中测试类里定义的是Pet类,但实际执行时都是调用Pet子类的方法。示例二中的代码就体现了多态性。
多态意味着在一次方法调用中根据包含的对象的实际类型(即实际的子类对象)来决定应该调用哪个方法,而不是由用来存储对象引用的变量的类型决定的。当调用一个方法时,为了实现多态的操作,这个方法既是在父类中声明过的,也必须是在子类中重写过的方法。
示例二中的Pet类声明为抽象类,因为其本身实例化没有任何意义,toHospital()方法声明为抽象方法。
提示:
抽象类不能被实例化。
抽象方法必须在抽象类里。
子类如果不是抽象类,则必须重写抽象类中的全部抽象方法。
abstract修饰的抽象方法没有方法体。
private关键字不能用来修饰抽象方法。

向上转型

子类向父亲的转换称为向上转型。
向上转型的语法格式如下:
<父类型><引用变量名>=new<子类型>();
之前介绍过基本数据类型之间的类型转换,举例如下:
(1)把int型常量或变量的值赋给double型变量,可以自动进行类型转换。

int i=5;
double d1=5;

(2)把double型常量或变量的值赋给int型变量,必须进行强制类型转换。

double d2=3.14;
int a=(int)d2;

实际上引用数据类型的子类和父类之间也存在着类型转换问题,如示例二中的代码。

//Pet为抽象父类,Dog为子类,Pet中包含抽象方法toHospital()
Pet pet=new Pet();//子类到父类的转换
//会调用Dog类的toHospital()方法,而不是Pet类的toHospital()方法,体现了多态
pet.toHospital();

Pet对象无法调用子类特有的方法。
总结子类转换成父类时的规则:
将一个父类的引用指向一个子类对象称为向上转型,系统会自动进行类型转换。
此时通过父类引用变量调用的方法是子类覆盖或继承了父类的方法,不是父类的方法。
此时通过父类引用变量无法调用子类特有的方法。

向下转型

前面已经提到,当向上转型发生后,将无法调用子类特有的方法。但是如果需要调用子类特有的方法,可以通过把父类转换为子类来实现。
将一个指向子类对象的父类引用赋给一个子类的引用,即将父类类型转换为子类类型,称为向下转型,此时必须进行强制类型转换。
如果Dog类中包含一个接飞盘的方法catchingFlyDisc(),这个方法是子类特有的,下面的代码就会存在问题:

//Pet为父类,Dog为子类,Pet中包含方法toHospital(),不包含catchingFlyDisc()
Pet pet=new Pet();     //子类到父类的转换
//会调用Dog类的toHospital()方法,而不是Pet类的toHOspital()方法,体现了多态
pet.toHospital();
pet.catchingFlyDisc();    //无法调用子类特有的方法

那么这里就需要做的是进行强制类型转换,将父类转换成子类,然后才能调用子类特有的方法。

Dog dog=(DOg)pet;//将Pet转换为Dog类型
dog.catchingFlyDisc();//执行Dog特有的方法

上述这种向下转型的操作对接口和抽象(普通)父类同样适用。
向下转型的语法:
<子类型><引用变量>=(<子类型>)<父类型的引用变量>

instanceof运算符

在向下转型的过程中,如果不是转换为真实子类类型,会出现类型转换异常。

//Pet为父类,Dog为子类,Bird为子类
Pet pet=new Dog();//子类到父类的转换
pet.toHospital();//会调用Dog类的toHospital()方法
Bird bird=(Bird)pet;//将Pet转换为Bird类会出错

在Java中提供了instanceof运算符来进行类型的判断。
示例三:

public class Test {
    public static void main(String[] args) {
    Pet pet=new Bird();
    //Pet pet=new Dog();
    pet.toHospital;
  if(pet instanceof Dog){
            Dog dog=(Dog)pet;
            dog.catchingFlyDisc();//执行狗狗特有的方法,即接飞盘
        }else if(pet instanceof Bird){
            Bird bird=(Bird)pet;
            bird.fly;//执行小鸟特有的方法,即飞翔
        }
    }
}

使用instanceof时,对象的类型必须和instanceof后面的参数所指定的类有继承关系,否则会出现编译错误。

多态的使用

多态的优势非常突出:
可替代性:多态已存在的代码具有可替代性。
可扩充性:多态对代码具有可扩充性。增加新的子类不影响已存在类的多态性、继承性,以及其他特性的运行和操作。实际上新加子类更容易获得多态功能。
接口性:多态是父类向子类提供的一个共同接口,由子类来具体实现。
灵活性:多态在应用中体现了灵活多样的操作,提高了使用效率。
简化行:多态简化了应用软件的代码编写和修改过程,尤其在处理大量对象的运算和操作时,这个优点尤为突出和重要。
在多态的程设计中,一般有以下两种主要的应用形式。

使用父类作为方法的形参

示例四:假如狗、猫、鸭3种动物被一个主人领养,这个主人可以控制各种动物叫的行为,实现一个主人类,在该类中定义控制动物叫的方法。
关键代码:

//主人类
public class Host {
    public void letCry(Animal animal){
        animal.cry();//调用动物叫的方法
    }
}
//以上为主人类代码,以下为调用代码
public class Test{
    public static void main(String[] args) {
        Host host=new Host();
        Animal animal;
        animal=new (Dog);
        host.letCry(animal);//控制狗叫
        animal.new Cat();
        host.letCry(animal);//控制猫叫
        animal=new Duck();
        host.letCry(animal);//控制鸭叫
    }
}

在实例四的主人控制动物叫的方法中,并没有把动物的子类作为方法参数,而是使用Animal父类。当调用letCry()方法时,实际传入的参数是一个子类的动物,最终调用的也是这个子类动物的cry()方法。

使用父类作为方法的返回值

使用父类作为方法的返回值,也是Java中实现和使用多态的主要形式。
示例五:假如3种动物被一个主人领养,这个主人可以根据其他人的要求任意送出一只宠物。送出的动物可以叫。
关键代码:

//主人类
public class Host {
    //赠送动物
    public void donateAnimal(String type){
        Animal animal;
        if(type=="dog"){
            animal=new Dog();
        }
        else if (type=="cat"){
            animal=new Cat();
        }else {
            animal=new Duck();
        }return animal;
    }
}
//以上为主人类代码,以下为调用代码
public class Test{
    public static void main(String[] args) {
        Host host=new Host();
        Animal animal;
      animal=host.donateAnimal("dog");
      animal.cry();//狗叫
        animal=host.donateAnimal("cat");
        animal.cry();//猫叫
    }
}

在上述代码中将父类Animal作为赠送动物方法的返回类型,而不是具体的子类,调用者人任然可以控制动物叫,动物叫的行为则由具体的动物类型决定。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值