Java--多态

1.概念:父类引用指向子类对象,从而产生多种形态。

   前边学继承的时候 定义了父类 Animal,子类Dog,Bird (继承了父类Animal)

   如果定义 Animal  a = new Dog();     Animal  a  就是父类引用(引用类型)   new Dog()子类对象(子类类型)  new Dog() 改为 new Bird () 也是成立的。

  •    二者具有直接或间接的继承关系时,父类引用可指向子类对象,即形成多态
  •    父类引用仅可以调用父类所声明的属性和方法,不可调用子类独有的属性和方法。

   实例:定义  Animal a1 = new Dog();  a1只能调用父类Animal 中的属性和方法,不能调用子类Dog中的属性和方法。

2.多态中的方法重写

   如果子类中重写了父类中的方法,以父类类型引用调用此方法时,优先执行父类中的方法还是子类中的方法?

   在实际运行过程中,依旧遵循重写原则,如果子类重写了父类中的方法,执行子类中重写后的方法,否则执行父类中的方法。

package com.monv.plat;
/**
 * 动物类
 * @author Administrator
 *
 */
public class Animal {
    //品种
    String  breed;
    //年龄
    int age;
    //性别
    String Sex;
    
    //
    public void eat() {
        System.out.println("吃......");
    }
    //
    public void sleep() {
        System.out.println("睡......");
    }
}
-----------------------------------------------------------------------
package com.monv.plat;

public class Dog extends Animal {
    //毛色--狗狗类定义的属性
    String furColor;
    //跑--狗狗类定义的方法
    public void run() {
        System.out.println(breed+"跑......");
    }
    @Override //重写了父类中eat()方法
    public void eat() {
        System.out.println(breed+"在吃狗粮!");
    }
}
-------------------------------------测试--------------------------------
package com.monv.plat;

public class TestDog {
    public static void main(String[] args) {
//        Animal animal = new Animal(); 通常实例化变量的写法
        //理解:1.逻辑上来讲 Dog is Animal 是成立的  2.语法上来讲 隐含自动类型转换 Dog类的范围小于Animal类的范围
        Animal a1 = new Dog();//用父类 Animal 创建变量a1 实例化Dog子类
        //调用属性和方法 a1只能调用父类的属性和方法
        a1.age = 2;
        a1.breed = "柯基";
        a1.Sex ="公";
        a1.eat();//在Dog中重写了父类中的eat方法 所以这里调用的是子类Dog的eat方法
        a1.sleep();
    }
}
结果:
柯基在吃狗粮!
睡......
-------------------------------------------------------------------------

3.多态的应用

  • 使用父类作为方法形参实现多态,使方法参数的类型更为宽泛

       例如:小明有很多动物,现在小明来喂动物,根据动物的类型,来执行不同动物eat的方法

package com.monv.plat;
/**
 * 动物类
 * @author Administrator
 *
 */
public class Animal {
    //品种
    String  breed;
    //年龄
    int age;
    //性别
    String Sex;
    //
    public void eat() {
        System.out.println("吃......");
    }
    //
    public void sleep() {
        System.out.println("睡......");
    }
}
-----------------------------------------------
package com.monv.plat;
public class Dog extends Animal {
    //毛色--狗狗类定义的属性
    String furColor;
    //跑--狗狗类定义的方法
    public void run() {
        System.out.println(breed+"跑......");
    }
    @Override //重写了父类中eat()方法
    public void eat() {
        System.out.println(breed+"在吃狗粮!");
    }
}
-----------------------------------------------------
package com.monv.plat;

public class Bird extends Animal{
    //毛色
    String furColor;
    //
    public void fly(){
        System.out.println("鸟在飞!");
    }
    @Override//重新父类中eat方法
    public void eat() {
        System.out.println("早起的鸟儿有虫吃");
    }
}
---------------------------------------------------------
package com.monv.plat;
/**
 * 主人类---喂食
* 利用方法重载在类中添加不同喂食方法 喂狗狗的 喂小鸟的 如果要添加新的喂食方法 需要再重写feed方法传递不同的参数 比较麻烦 导致重载的方法过多 而且需要多次修改Master这个类
* 由此 这里可以用多态优化 方法的形参不定义具体子类的参数类型 用父类Animal来定义 这样的话 用一个方法就可以执行不同的喂食方法 *
@author Administrator * */ public class Master { String name; // //喂狗方法 // public void feed(Dog dog){ // System.out.println(this.name+"给狗狗喂食"); // dog.eat(); // } // //喂鸟的方法 // public void feed (Bird bd) { // System.out.println(this.name+"给小鸟喂食"); // bd.eat(); // }

//使用多态优化 父类作为方法的参数
public void feed(Animal animal){ System.out.println(this.name+"喂食"); animal.eat();//由于子类把父类的方法重写了 所以这里调用的是子类的方法 } } -----------------------------测试--------------------------------------- package com.monv.plat; public class TestMaster { public static void main(String[] args) { Master ma = new Master(); ma.name = "小明"; //定义狗狗 柯基 Dog keji = new Dog(); keji.breed ="柯基"; ma.feed(keji); //定义鸟儿 Bird bd = new Bird(); ma.feed(bd); } }
结果: 小明喂食 柯基在吃狗粮! 小明喂食 早起的鸟儿有虫吃
-------------------------------------------------------------------------

 

  • 使用父类作为方法返回值实现多态,使方法可以返回不同子类对象
package com.monv.plat;
/**
 * 主人类---喂食和购买
 * @author Administrator
 *
 */
public class Master {
    String name;
    
//    //喂狗方法
//    public void feed(Dog dog){
//        System.out.println(this.name+"给狗狗喂食");
//        dog.eat();
//    }
//    //喂鸟的方法
//    public void feed (Bird bd) {
//        System.out.println(this.name+"给小鸟喂食");
//        bd.eat();
//    }
    //使用多态 多态的第一种用法 作为方法的形参
    public void feed(Animal animal){
        System.out.println(this.name+"喂食");
        animal.eat();
    }
    //买  根据传递的type值 来判断购买的是狗狗 还是小鸟(多态的第二种用法 作为方法的返回值)
    public Animal buy(int type){
        Animal animal = null;
        if (type == 1){
            animal = new Dog();
        } else if (type == 2){
            animal = new Bird();
        }
        return animal;
    }
    
}
---------------------------测试-----------------------------------------
package com.monv.plat;

import java.util.Scanner;

public class TestBuy {
    public static void main(String[] args) {
        System.out.println("--------欢迎来到格兰动物市场--------");
        System.out.println("-------1.购买狗狗  2.购买小鸟-------");
        System.out.println("请选择:");
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();
        Master master = new Master();
        Animal animal = master.buy(choice);//animal用来接收 传入不同choice值返回的类型
        if (animal!=null){
            System.out.println("购买成功");
        }else {
            System.out.println("输入错误,购买失败!");
        }
        
    }
}

------------------------------------------------------------------------

4.类型转换     上例中 master.buy返回的类型是Animal类 只能访问Animal类中的属性和方法 如果想要访问子类Dog中的方法,怎么办?------用类型转换

  •   向上转型(装箱): 

            Animal a = new Dog();   父类引用中保存真实子类对象,称为向上转型(即多态核心概念)

            注意:a仅可调用Animal中的方法和属性。

  •   向下转型(拆箱)  前提:先向上转型

          Animal a = new Dog(); (前提)

            Dog keji = (Dog)a;---将父类引中的真实子类对象,强转回子类本身类型,称为向下转型。

            注意:只有转回子类真实类型,才可以调用子类独有的属性和方法。keji可调用Dog类中独有的属性和方法。

  

package com.monv.plat;

import java.util.Scanner;

public class TestBuy {
    public static void main(String[] args) {
        System.out.println("--------欢迎来到格兰动物市场--------");
        System.out.println("-------1.购买狗狗  2.购买小鸟-------");
        System.out.println("请选择:");
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();
        Master master = new Master();
        Animal animal = master.buy(choice);//animal用来接收 传入不同choice值返回的类型
        if (animal!=null){
            System.out.println("购买成功");
            Dog keji =(Dog)animal;//向下类型转换
            keji.run();//调用的是Dog类中的方法
        }else {
            System.out.println("输入错误,购买失败!");
        }
        
    }
}
------------------------------------------------
输入1 则返回结果; 如果输入 2 则会报错 为什么?
因为:输入2 animal接收的是Bird类,把Bird类向下类型转换为Dog类则会类型转换异常的错误
错误信息(Exception in thread
"main" java.lang.ClassCastException: com.monv.plat.Bird cannot be cast to com.monv.plat.Dog at com.monv.plat.TestBuy.main(TestBuy.java:16))

 

5.类型转换异常

   向下转型时,如果父类引用中的子类对象类型和目标类型不匹配,则会发生类型转换异常。

   如何处理这种异常,用关键字   instanceof

   向下转型前,应判断引用中的对象真实类型,保证类型转换的正确性。

   语法:引用  instanceof 类型   //返回boolean类型结果

package com.monv.plat;

import java.util.Scanner;

public class TestBuy {
    public static void main(String[] args) {
        System.out.println("--------欢迎来到格兰动物市场--------");
        System.out.println("-------1.购买狗狗  2.购买小鸟-------");
        System.out.println("请选择:");
        Scanner input = new Scanner(System.in);
        int choice = input.nextInt();
        Master master = new Master();
        Animal animal = master.buy(choice);//animal用来接收 传入不同choice值返回的类型
        if (animal!=null){
            System.out.println("购买成功");
            if(animal instanceof Dog){//如果animal是Dog类型 则转换为Dog类型
                Dog keji =(Dog)animal;//向下类型转换
                keji.run();//调用的是Dog类中的方法    
            }else if (animal instanceof Bird){//如果animal是Bird类型 则转换为Bird类型
                Bird yw = (Bird)animal;
                yw.fly();
            }
            
        }else {
            System.out.println("输入错误,购买失败!");
        }
    }

6.总结

   多态的两种应用场景:

  • 使用父类作为方法的形参,实现多态。(feed方法)

    调用方法时,可传递的实参类型包括:本类对象 + 其所有的子类对象。

  • 使用父类作为方法的返回值,实现多态。(buy方法)

    调用方法后,可得到的结果类型包括:本类对象 + 其所有的子类对象。

   多态作用:

  • 屏蔽子类间的差异
  • 灵活,耦合度低
posted @ 2020-08-11 16:46  改Bug的小魔女  阅读(209)  评论(0编辑  收藏  举报