面向对象——修改动物腿数(使用接口并抛出异常)

 

 

需求

1.输出各种动物叫声

2.输出各种动物腿数

3.实现修改参数功能

效果如下:

 

 

 实现思路

  分析:根据给出的类图,我们可以看出有3种动物,猫、鸭子和海豚,他们都属于父类Animal,而他们共有的特征(属性)在此项目有名字和叫声(也可以定义为方法,在此项目中我定为动物的属性),而腿数只有猫和鸭子有,海豚是没有的,所以这个项目要求我们修改腿数只有猫和鸭子,用接口实现这个修改方法,而且输入的腿数不正确,需要抛出异常,且程序要正常运行。

 

  首先,根据类图和分析,我们先写出Animal(父类),代码如下:

 

package com.animal;
/**
 * 动物类
 * @author Administrator
 *
 */
public abstract class Animal {

    private String name;        //动物名字
    private String voice;       //动物叫声
    private int leg;       //动物腿数
    
    public int getLeg() {
     return leg;
    }
    public void setLeg(int leg) {
        this.leg = leg;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getVoice() {
        return voice;
    }
    public void setVoice(String voice) {
        this.voice = voice;
    }
    public Animal(){}
    
//没有腿数的带参构造方法,给海豚初始化
public Animal(String name,String voice) { this.name=name; this.voice=voice; }
//带腿数参数的构造方法,给猫和鸭子初始化
public Animal(String name,int leg,String voice) { this.name=name; this.leg=leg; this.voice=voice; } }

  可以看出父类的属性有名字、叫声、腿数,那么海豚继承这个父类也会有腿数属性,但是海豚是没有腿数的,那么我们可以写两个构造方法,一个是带腿数的构造方法,一个是不带腿数的构造方法,我们在给海豚初始化的时候使用不带腿数参数的构造方法就好了。

 

  父类写完了,我们接下来写父类的子类,猫、鸭子和海豚类!

猫类:

public class Cat extends Animal     {
    
    public Cat(){}
    public Cat(String name,int leg,String voice) {
        super(name,leg,voice);
    
    }
}

 

鸭子类:

public class Duck extends Animal {
    
    public Duck(){}
    public Duck(String name,int leg,String voice) {
        super(name,leg,voice);
        
        
    }
}

海豚类:

public class Delph extends Animal {

    public Delph(){}
    public Delph(String name,String voice) {
        super(name,voice);
    }
    
}

  现在三个子类都写好各自的构造方法(为了方便等下初始化属性的时候赋值);

  接下来还有一个AnimalMgr类和一个接口LuSheng,这个接口就是为了实现修改动物的数据(名字和腿数),但是在修改这个腿数之前,我们可以发现这个程序运行的时候,先输出了一个界面,展示了动物的信息,并且输入0的时候,修改完宠物的信息之后,还是会弹出这个界面,可以用do-while循环,那么我们可以先写好这个界面,也就是程序的整体的框架,修改腿数的功能稍后再写。

  分析一下这个界面,我们可以发现,第一行只是输出那些字而已,很简单,System.out就可以了,但是下面展示的动物信息,输出了猫、鸭子、海豚的信息,我们可以很容易就想到数组,遍历输出。(不要问我为什么很容易想到数组,因为所以没有道理)而用面向对象的思想来思考,这三个动物都属于动物,那么我们可以定义一个动物类的数组,然后把猫、鸭子、海豚都放到这个动物数组里面,然后给他们赋值遍历输出这个数组就输出了各个动物的信息了。

  那么接下来我们就在AnimalMgr类实现这个界面:  

 1 public class AnimalMgr {    
 3     Animal [] animal=new Animal[3];    //创建一个动物数组,存放动物信息
 4     
 5     public AnimalMgr() {
 6         animal[0]=new Cat("小猫",4,"喵喵喵");
 7         animal[1]=new Duck("小鸭",2,"嘎嘎嘎");
 8         animal[2]=new Delph("海豚","嘤嘤嘤");    
 9         Scanner input=new Scanner(System.in);
10         int type=0;
11         do {
12             System.out.println("动物名字\t腿的条数\t动物叫");
13             
14             System.out.println("是否修改数据:按0进行修改,其他数字退出");
15             type=input.nextInt();
16             if(type==0) {
17                 //进行修改操作
18             }
19         }while(type==0);
20         
21     }

  我在AnimalMgr类里面声明了一个动物数组,重写了一个无参构造函数,将程序的主体放入这个无参构造函数内,然后创建了三个对象,小猫、鸭子和海豚,接着用do-while循环实现程序的循环操作。我们写一个Text类,只需要创建AnimalMgr的对象就可以了(整个main方法只有一行代码,就是创建AnimalMgr的对象,因为我的整个程序都在AnimalMgr类的无参构造方法AnimalMgr中),测试效果如下:

 

 

 

 

  接下来我们就需要将动物的信息输出,也就是存在动物数组里的遍历输出,我们可以在AnimalMgr类下面写一个方法showInfo遍历动物数组,输出信息:

  public void showInfo() {
        for (Animal animal2 : animal) {
            System.out.println(animal2.toString());
        }
    }
    

  forech遍历输出,再使用Object类的toString方法,但是这时候输出的是数组对象的地址,那么我们可以重写一下toSting方法,我们可以在Animal类下重写:

package com.animal;
/**
 * 动物类
 * @author Administrator
 *
 */
public abstract class Animal {

    private String name;        //动物名字
    private String voice;        //动物叫声
    private int leg;            //动物腿数
    
    public int getLeg() {
        return leg;
    }
    public void setLeg(int leg) {
        this.leg = leg;
    }
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getVoice() {
        return voice;
    }
    public void setVoice(String voice) {
        this.voice = voice;
    }
    public Animal(){}
    public Animal(String name,String voice) {
        this.name=name;
        this.voice=voice;
    }
    
    public Animal(String name,int leg,String voice) {
        this.name=name;
        this.leg=leg;
        this.voice=voice;
    }
    
    /**
     * 重写toString方法
     */
    public String toString() {
        return this.name+"\t"+this.leg+"\t"+this.voice;
    }
}

  

   这时候我们再次测试,会发现,海豚也输出了腿数,为0,这是因为我们重写的toString方法中,return有返回leg这个参数,即使海豚的构造方法和赋值都没有给这个参数,但是程序会默认给一个0,这时候我们可以在海豚类中再次重写toString方法:

public class Delph extends Animal {

    public Delph(){}
    public Delph(String name,String voice) {
        super(name,voice);
    }
    

    /**
     * 重写海豚toString方法
     */
public String toString() {    
        return this.getName()+"\t\t"+this.getVoice();
    }
}

再次运行程序:

  可以看到现在我们程序的界面和运行已经符合了需求,那么下一步,我们要做的就是修改腿数的操作了,对于修改腿数这个操作我们是通过LuSheng接口来实现的,而且只有小猫和小鸭可以修改,所以我们要在Cat类和Duck类中实现这个接口,而需求中,当猫输入的腿数不符合4的时候,鸭子不符合2的时候抛出异常,且输出程序界面(即程序异常,程序仍然会继续运行),所以我们先创建一个接口类LuSheng:

package com.animal;
/**
 * 用于修改动物腿数的接口
 */
public interface LuSheng {
    void chang ()throws Exception;
}

  在这个接口中写了一个chang()方法,且这个方法抛出了一个异常,因为这个接口的实现类Cat和Duck类中实现这个接口的方法chang()也需要抛出异常,会抛给这个接口,所以这个接口中的chang()方法也需要继续往上抛异常。

  我们先写Cat类的修改方法(为了方便,我将修改名字的方法也写在了chang()方法中):

package com.animal;

import java.util.Scanner;

public class Cat extends Animal implements LuSheng {
    
    public Cat(){}
    public Cat(String name,int leg,String voice) {
        super(name,leg,voice);
    
    }

    /**
     * 实现LuSheng接口chang方法,修改猫腿数,输入错误,抛出异常
     */
    public void chang() throws Exception {     //实现接口方法抛出异常,关键字thorws
        Scanner input=new Scanner(System.in);
        System.out.println("请输入猫的名字:");
        String name=input.next();
        this.setName(name);              //将输入的名字通过Set方法修改父类name属性,修改名字
        System.out.println("请输入猫的腿数:");
        int leg=input.nextInt();
        if(leg!=4) {            
            throw new Exception("猫的腿数为4!");  //当输入的腿数不为4的是和,方法体中抛出一个异常信息  throw
        }else {
            this.setLeg(leg);             //输入的是4的话就将4修改父类中的leg
        }
    }

    
    
}

Duck类:

package com.animal;

import java.util.Scanner;

public class Duck extends Animal implements LuSheng{
    
    public Duck(){}
    public Duck(String name,int leg,String voice) {
        super(name,leg,voice);
    }
    /**
     * 实现LuSheng接口chang方法,修改鸭子腿数,输入错误,抛出异常
     */
    public void chang() throws Exception{
        Scanner input=new Scanner(System.in);
        System.out.println("请输入鸭的名字:");
        String name=input.next();
        this.setName(name);
        System.out.println("请输入鸭的腿数:");
        int leg=input.nextInt();
        if(leg!=2) {
            throw new Exception("鸭的腿数为2!");
        }else {
            this.setLeg(leg);
        }    
    }    
}

Delph类(只需要修改名字,不需要实现接口,所以写一个方法修改名字就好了,也叫chang()):

package com.animal;

import java.util.Scanner;

public class Delph extends Animal {

    public Delph(){}
    public Delph(String name,String voice) {
        super(name,voice);
    }
    //修改海豚名字的方法:
    public void chang() {
        Scanner input=new Scanner(System.in);
        System.out.println("请输入海豚的名字:");
        String name=input.next();
        this.setName(name);
    }
    /**
     * 重写海豚toString方法
     */
public String toString() {    
        return this.getName()+"\t\t"+this.getVoice();
    }
}

  修改的方法已经写完了,我们只需要在type==0的判断操作后面进行调用这些修改方法就可以了,按照程序的顺序,首先是猫,然后是鸭子,最后是海豚,而我们在创建这个动物数组的时候,是运用了子类指向父类的数据类型创建的对象,也就是多态的实现,但是chang()方法是各个子类独有的,指向父类的数据类型是调用不了子类独有的方法的,所以我们可以遍历这个数组,当这个数据类型是猫的时候,我们强制向下转型,就可以调用子类的方法了,整个AnimalMgr代码如下:

package com.animal;


import java.util.Scanner;

public class AnimalMgr {
    //创建对象数组
    Animal [] animal=new Animal[3];
    
    public AnimalMgr() {
        animal[0]=new Cat("小猫",4,"喵喵喵");            //创建猫对象,放进动物数组animal[0]中
        animal[1]=new Duck("小鸭",2,"嘎嘎嘎");            //创建鸭子对象,放进动物数组animal[1]中
        animal[2]=new Delph("海豚","嘤嘤嘤");            //创建海豚对象,放进动物数组animal[2]中
        Scanner input=new Scanner(System.in);
        int type=0;
        do {
            System.out.println("动物名字\t腿的条数\t动物叫");
            showInfo();
            System.out.println("是否修改数据:按0进行修改,其他数字退出");
            type=input.nextInt();
            if(type==0) {
                for (Animal animal2 : animal) {            //遍历数组
                    if(animal2 instanceof Cat) {        //当前对象为猫类的时候,强制向下转型
                        try {
                            ((Cat) animal2).chang();    //调用Cat类的chang()方法,且捕抓异常,输出异常信息之后调出循环
                        } catch (Exception e) {
                            e.printStackTrace();
                            break;
                        }    
                    }else if(animal2 instanceof Duck) {        //当前对象为鸭子类的时候,强制向下转型
                        try {
                            ((Duck) animal2).chang();    //调用Duck类的chang()方法,且捕抓异常,输出异常信息之后调出循环
                        } catch (Exception e) {
                            e.printStackTrace();      
                            break;
                        }    
                    }else {
                        ((Delph)animal2).chang();
                    }
                    
                }
                
            }
        }while(type==0);
        
    }

    /**
     * 展示动物信息
     */
    public void showInfo() {
        for (Animal animal2 : animal) {
            System.out.println(animal2.toString());
        }
    }
    
    
}

  当我们在调用各个类的实现接口的方法chang()方法的时候,我们可以用try-catch处理异常,且catch处理完异常之后,break退出forech循环,返回主界面,最终实现效果:

 

总结

  程序是比较简单,但是综合性其实比较强,对象数组,接口,异常,重写,当然实现的方法有很多,比如如果将叫声定义为父类的抽象方法,各个子类再去重写实现,遍历的时候在调用这个类的叫声的方法就可以。还有将腿数leg弄为Cat和Duck的私有属性,在通过接口进行传参设置,但是我个人觉得leg属性放在父类Animal中更符合现实逻辑,这就是我面向对象的修改动物腿数(使用接口并抛出异常)的全部思路。

猜你喜欢

转载自www.cnblogs.com/EasyInsomnia/p/10087759.html