面向物件——修改動物腿數(使用介面並丟擲異常)
需求
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中更符合現實邏輯,這就是我面向物件的修改動物腿數(使用介面並丟擲異常)的全部思路。