首页 > 技术文章 > 多态

qianwangxingfu 2016-11-18 22:40 原文

1.运行下面代码,回答问题

(1)源代码

public class ParentChildTest {

   public static void main(String[] args) {

      Parent parent=new Parent();

      parent.printValue();

      Child child=new Child();

      child.printValue();

     

      parent=child;

      parent.printValue();

     

      parent.myValue++;

      parent.printValue();

     

      ((Child)parent).myValue++;

      parent.printValue();

     

   }

}

 

class Parent{

   public int myValue=100;

   public void printValue() {

      System.out.println("Parent.printValue(),myValue="+myValue);

   }

}

class Child extends Parent{

   public int myValue=200;

   public void printValue() {

      System.out.println("Child.printValue(),myValue="+myValue);

   }

}

(2)问题

程序运行的结果:

解释:首先定义Parent类的变量,会调用Parent类的printValue函数,此时myValue=100;第二个定义了Child一个类,所以会调用child的函数,myValue=200;第三个让parent=child,这样就会调用child的函数,myValue=200;第四个parent.myValue++,会在myValue上加一,但是parent=child仍然成立,所以还是会调用child的函数,myValue=200;最后一个强制转换,所以加1之后myValue也会变化,还会继续调用child的函数。

总结:

当子类与父类拥有一样的方法,并且让一个父类变量引用一个子类对象时,到底调用哪个方法,由对象自己的“真实”类型所决定,这就是说:对象是子类型的,它就调用子类型的方法,是父类型的,它就调用父类型的方法。这也就会用到多态性。

如果子类与父类有相同的字段,则子类中的字段会代替或隐藏父类的字段,子类方法中访问的是子类中的字段(而不是父类中的字段)。如果子类方法确实想访问父类中被隐藏的同名字段,可以用super关键字来访问它。

如果子类被当作父类使用,则通过子类访问的字段是父类的!

2.多态的含义与用途(动物园)

Zoo1

 

package zoo1;

public class Zoo

public static void main(String args[])

   {

      Feeder f = new Feeder("小李");

      // 饲养员小李喂养一只狮子

      f.feedLion(new Lion());

      // 饲养员小李喂养十只猴子

      for (int i = 0; i < 10; i++)

      {

         f.feedMonkey(new Monkey());

      } 

      // 饲养员小李喂养5只鸽子

      for (int i = 0; i < 5; i++)

      {

         f.feedPigeon(new Pigeon());

      }

   }

}

class Feeder

{

   public String name;

   public Feeder(String name)

   {

      this.name = name;

   }

   public void feedLion(Lion l)

   {

      l.eat();

   }

   public void feedPigeon(Pigeon p)

   {

      p.eat();

   }

   public void feedMonkey(Monkey m)

   {

      m.eat();

   }

}

class Lion

{

   public void eat()

   {

      System.out.println("我不吃肉谁敢吃肉!");

   }

}

class Monkey

{

   public void eat()

   {

      System.out.println("我什么都吃,尤其喜欢香蕉。");

   }

}class Pigeon

{

   public void eat()

   {

      System.out.println("我要减肥,所以每天只吃一点大米。");

   }

}

缺点:要多次循环,每个类中都有相同的函数,但是没有任何联系,如果要增加一个要求,要多次修改。

Zoo2

Feeder类的三个喂养方法现在可以合并为一个feedAnimal()方法,注意它接收一个类型为Animal参数,而不是三个具体的动物类型。依据多态特性,此方法将可以接收任何一个派生自Animal类的子类对象

先定义一个Feeder类,定义animal类,其中有一个eat方法,只有函数名,没有函数内容。其他三个类继承这个类方法,定义适合自己的方法,覆盖;这是抽象类。

Zoo3

修改feedAnimals方法,让它接收一个Animal数组,现在只需要一句代码,就可以模拟出喂养一批各种各样的动物的过程

Zoo4

package zoo4;

import java.util.Vector;

 

public class Zoo {

 

    public static void main(String args[]) {

        Feeder f = new Feeder("小李");

        Vector<Animal> ans = new Vector<Animal>();

 

        //饲养员小李喂养一只狮子

        ans.add(new Lion());

        //饲养员小李喂养十只猴子

        for (int i = 0; i < 10; i++) {

            ans.add(new Monkey());

        }

        //饲养员小李喂养5只鸽子

        for (int i = 0; i < 5; i++) {

            ans.add(new Pigeon());

        }

        f.feedAnimals(ans);

    }

}

 

class Feeder {

 

    public String name;

 

    Feeder(String name) {

        this.name = name;

    }

 

    public void feedAnimals(Vector<Animal> ans) {

        for (Animal an : ans) {

            an.eat();

        }

    }

}

 

abstract class Animal {

 

    public abstract void eat();

}

 

class Lion extends Animal {

 

    public void eat() {

        System.out.println("我不吃肉谁敢吃肉!");

    }

}

 

class Monkey extends Animal {

 

    public void eat() {

        System.out.println("我什么都吃,尤其喜欢香蕉。");

    }

}

 

class Pigeon extends Animal {

 

    public void eat() {

        System.out.println("我要减肥,所以每天只吃一点大米。");

    }

}

第二次重构之后,Feeder类的feedAnimals()方法接收的是一个Animal数组,这有一个限制,就是只能创建固定个数的数组,无法动态地增减动物个数。修改feedAnimals方法,让其接收一个元素数目可变的对象容器,利用Vector<T>,Vector<T>是JDK中提供的一个对象集合,可以随时向其中加入或移除对象。

总结:

应用多态,可以使我们的代码具有更强的适用性。当需求变化时,多态特性可以帮助我们将需要改动的地方减少到最低限度。使用多态好处:当要修改程序并扩充系统时,你需要修改的地方较少,对其它部分代码的影响较小

3. 用多态的方法模拟ATM操作流程。

(1)源代码

import java.util.Scanner;

/*

 * ATM机取款

 */

//陈晓阳 20153253

public class Money1 {//执行类

   public static void main(String args[])

   {

      System.out.println("请插卡!");

     

         System.out.println("请选择语言:");

         int i1;

         Scanner inm=new Scanner (System.in);

         i1=inm.nextInt();

         if(i1==1)//英语

            {System.out.println("英语");}

         if(i1==2)//汉语

            {System.out.println("汉语");}

        

         Account ac=new Account("12345678901","zhangsan","2016/11/15","098765",6000);

         String i1m;//密码

         System.out.println("请输入密码:");

         Scanner inmm=new Scanner (System.in);

         i1m=inmm.next();

         while(i1m.equals(ac.mima))

         {System.out.println("请选择操作数:1 取款     2 存款    3 转账    4 退卡");

            int i;

            Scanner in=new Scanner (System.in);

            i=in.nextInt();

            switch(i)

            {

            case 1:

                //System.out.println("请输入密码:");

                String aa;

                Scanner in1=new Scanner (System.in);

                aa=in.nextLine();

                ac.withdraw();

                break;

            case 2://存款

                ac.cunqian();

                break;

            case 3://转账

                ac.zhuanzhang();

                break;

            case 4:

                System.out.println("退卡");break;

            default  :

                break;

            }

         }

         }

   }

abstract class ATM//定义抽象类

{

   public abstract void withdraw();

   public abstract void cunqian();

   public abstract void zhuanzhang();

}

class Account extends ATM//

{

   String num;//长度11位

   String name;

   String Date;

   String mima;

   //int chaozuo[]={1,2,3,4,5};

   double yue;//

   Account(String n,String na,String d,String m,double y)

   {

      num=n;name=na;Date=d;mima=m;yue=y;

     

   }

   public void withdraw()//取款

   {

      System.out.println("请选择取款金额!100元、500元、1000元、1500元、2000元、5000元、其他金额");

      int a;

      Scanner in2=new Scanner (System.in);

      a=in2.nextInt();

      if(yue>a){yue=yue-a;System.out.println("余额"+yue);}

      else System.out.println("余额不足!");

   }

   public void cunqian()//存款

   {

      System.out.println("请输入存款金额!");

      int a1;

      Scanner a11=new Scanner (System.in);

      a1=a11.nextInt();

      yue=yue+a1;

      System.out.println("余额"+yue);

   }

   public void zhuanzhang()//转账

   {

      System.out.println("请输入转账卡号");

      String a2;

      Scanner a12=new Scanner (System.in);

      a2=a12.nextLine();

      System.out.println("请输入转账的金额:");

      int a3;

      Scanner a13=new Scanner (System.in);

      a3=a13.nextInt();

      if(yue>a3)

      {yue=yue-a3;System.out.println("余额"+yue);System.out.println("转账成功!");}

      else System.out.println("余额不足!");

   }

}

 

(3)先定义一个抽象类,在类中写上函数名,没有函数体,再定义一个类,继承抽象类,函数中有要有抽象类中的所有函数,并定义为public类型的,在主函数中调用这些函数。

 

推荐阅读