|
4.5 实现了接口的邮件类例子
这一节我们将4.3节邮件类的例子加以改进和扩展,加入有关接口的内容,以说明接口和多继承的概念。
首先定义一个名为MailPost的接口,其中没有定义变量,而是给出两个有关邮寄方法原型。
calPrice()计算邮费并以浮点数形式返回;
post()完成邮寄。
例4.11 接口MailPost。
//MailPost.java
package ch4package;
public interface MailPost{
public float claPrice();
public void post();
}
接下来在包裹Parcel和汇款Remittance的基础上分别派生出可邮寄的包裹和汇款:PostParcel和PostRemit两个子类。
例4.12 子类PostParcel和PostRemit。
---------------------------------
//PostParcel.java
package ch4package;
import java.lang.*;
public class PostParcel extends Parcel implements MailPost{
protected int postage;
protected boolean postable;
protected boolean posted;
PostParcel(Ttring address1,String address2,int w,intp){
//构造方法
super(address1,address2,w);
postage=p;
postable=false;
posted=false;
}
public float calPrice(){//计算邮资
return((float)0.05*weight);
}
public void post(){//邮寄包裹
float price=calPrice();
postable=(price<=postage);
posted=true;
}
public void showMe(){//显示邮件信息
float price=calPrice();
System.out.println("Postable Parcel:" ;
System.out.println("\tFrom:" +fromAddress+\tTo"
+toAddress);
System.out.println("\tWeigth +weigth+"g\tPostage:"
+postage+"Yuan" ;
if(posted){
if(postable)System.out.println("\tIt has been
posted !" ;
else{
System.out.println("\tIt needs more postage:" ;
System.out.println("\tThe current postage
is:"+postage+"Yuan" ;
System.out.println("\t\tThe price is:"+price+"Yuan" ;
}
}
}
}
//PostRemit.java
package ch4package;
import java.lang.*;
public class PostRemit exteds Remittance implements MailPost{
protected int postage;
portected boolean postable;
protected boolean posted;
PostRemit(String address1,String address2,int m,int p){
//构造方法
super(address1,address2,m);
postage=p;
postable=false;
posted=false;
}
public float calPrice(){//计算邮资
float price=cealPrice();
postable=(price<=postage);
posted=true;
}
public void showMe(){//显示邮件信息
float price=calPrice();
System.out.println("Postable Remit:" ;
System.out.println("\tFrom:"+fromAddress+"\tTo:"
+toAddress);
System.out.println("\tMoney:"+money+"Yuan"+"\tPostage:"
+postage+"Yuan" ;
if(posted){
if(postable)System.out.println("\tIt has been
posted!" ;
else{
System.out.println("\tIt needs more postage:");
System.out.println("\t\tThe current postage is:"
+postage+"Yuan");
System.out.println("\t\tThe price is:"
+price+"Yuan");
}
}
}
}
---------------------------------
这两个类都实现了接口MailPost。由于两个类非常相似,我们仍然重点讲解其中一个:类PostParce。
PostParcel仍是包ch4package中的一员,它是类Parcel的子类(extends Parcel),又实现了接口MailPost(implements MailPost):
public class PostParcel extends Parcel implements MailPost
在Parcel的基础上,它新增加了三个变量:
postage,posted,postable
其中整型的postage用来记录邮寄人提供的邮资,布尔型的posted和postable分别用来记录是否被尝试邮寄过以及邮寄是束成功。在PostParcel的构造方法中,第9行语句
super(address1,address2,w);
调用了它的父类Parcel的构造方法,设定它从Parcel中继承的变量寄出地址、寄达地址和重量的初值。这就是我们在前面提到过的super变量在构造方法中的用途:调用父类的相应构造方法。这样做的一个好处是可以重用父类的代码,然后PostParcel就只需设定邮资,并将posted和postable初值都置为false。
PostParcel和PostRemit都实现了接口MailPost,国而在它们的定义中,都必须给出方法calPrice()和post()的具体实现。在PostParcel中,为了简单起见,邮费只是根据重量每克收到0.05元,而不考虑寄达的距离,如语句第15行:
return ((float)0.05*weight);
在post()方法中,将计算所得邮资与瑞有邮费加以比较,若邮费已够将postable设为true,包裹可邮寄;否则postable为false,包裹不可邮寄。无论postable取值如何,都已试图邮寄,所以将posted置为true。处理过程见第18行至20行。
最后一个方法是showMe()。在这里,PostParcel重写(Overriding)了它的父类Parcel中的同名方法。当包裹尚未被试图邮寄过,则在基本信息后附加有关的邮寄信息,若未邮寄成功,给出所需最费提示。
PostRemit类的基本构成与PostParcel是一致的,读者可以自己试着读懂它的源文件。
在包ch4package中,类Mails,Parcel,Remittance以及ShowMails都无需改动,只有最后的可执行类Show需要相应的修改。它的源程序如下。
例4.13 可执行类Show程序文件。
-------------------------
//Show.java
1: package ch4package;
import java.lang.*;
2: import java.io.*;
3:
4: public class Show{
5: public static ShowMails board=new ShowMails();
6: public static void main(String args[])throws IOException{
7: boolean finished=false;
8: BufferedReader in =new BufferedReader(new InputStreamReader(System.in));
9: while(!finished){//添加邮件
10: System.out.print("\nDo you want to add mails(Y/N)?");
11: System.out.flush();
12: char ch=in.readLine().charAt(0);
13: if('Y'==Character.toUpperCase(ch)){
14: System.out.println("Address information:");
15: System.out.print("\tFrom:");//输入地址信息
16: System.out.flush();
17: String address1=in.readLine();
18: System.out.print("\tTo:");
19: System.out.flush();
20: String address2=in.readLine();
//选择邮件种类
21: System.out.print("Choose the mail type:1-Parcel
2-Remittance ");
22: System.out.flush();
23: ch=in.readLine().charAt(0);
24: if('1'==ch){//输入包裹重量
25: System.out.print("Parcel\tWeight:");
26: System.out.flush();
27: int w=getInt();
//是否寄出邮件
System.out.print("Do you want to post it(Y/N?");
System.out.flush();
ch=in.readLine().charAt(0);
if('Y'==Character.toUpperCase(ch)){//输入邮资
System.out.println("You want to post in,then
input your postage:");
System.out.flush();
int p=getInt();
//可邮寄包裹
PostParcel pa=new
PostParcel(address1,address2,w,p);
board.putMails(pa);
}
//不可邮寄包裹
else{Parcel pa=new Parcel(address1,address2,w);
board.putMails(pa);}
}
if('2'==ch){
System.out.print("Remittance\tMoney:");
System.out.flush();
int m=getInt();
System.out.print("Do you want to post it(Y/N)?");
System.out.flush():
ch=in.readLine().charAt(0);
if('Y'==Character.toUpperCase(ch)){
System.out.println("You want to post it,then input
postage:");
System.out.flush();
int p=getInt();
//可邮寄汇款
PostRemit re=new PostRemit(address1,address2,m,p);
board.putMails(re);
}
//不可邮寄汇款
else{Remittance re=new Remittance(address1,address2,m);
board.putMails(re);}
}
}
else finished=true;
}
System.out.println("");
board.showAll();//显示邮件信息
post();
}
public static int getInt() throws IEOxception{
BufferedReader in=new BufferedReader
(new InputStreamReader(System.in));
String st=in.readLine();
Integer i=new Integer(st);
return i.intValue();
}
private static void post()throws ClassCastException,IOException{
int n\board.mailnum();
if(n!=0){
System.out.println("You have "+n+" mails");
boolean end=false;
//检查邮寄情况
while(!end){
System.out.print("\nInput the mail NO you want to check the
result(输0退出):");
System.out.flush();
int i=getInt();
if(i!=0){
try{
Mails obj=board.getMails(i-1);
post((MailPost)obj);
obj.showMe();
}catch(ClassCastException ex){
System.out.println("Mail is not postable!");}
}
else end=true;
}
}
}
private static void post(MailPost obj){
obj.calPrice();
obj.post();
}
}
-------------------------
与第三节例4.8中类的Show相比,改动后的Show的main方法增加了询问是否要将邮件设为可邮寄类型的功能以及相应的处理段,并调用Post()方法邮寄邮件并给出邮寄情况说明。类Show定义了两个post方法来实惠邮寄。这两个方法虽同名,但参数不同,完成的功能也大相径庭。
第72行至92行的第一个post方法没有参数。它首先给出现有邮件数量,然后根据输入的邮件号通过ShowMails的getMails方法取得邮件,再调用第二个post方法实际将邮件寄出;当输入的邮件号为零时结束。在调用第二个post方法时,需要将邮件显式转换为接口类MailPost:
83:Mails obj=bord.getMails(i-1);
84 ost((MailPost)obj);
因为PostParcel和PostRemit都实现了接口MailPost,都支持这样的转换,就可以通过种形式从功能上将它们统一起来。如果该邮件所属的类没有实现接口MailPost ,如类Parcel或类Remittance,这样的类型转换就不能实现,将引发类型转换异常(ClassCastException),不再转去调用post方法,而由catch结构给出“邮件无法被邮寄”的报错信息:
86:}catch(ClassCastException ex){
87: System.out.println("Mail is not postable!");}
其中的try-catch结构是Java中异常处理的典型结构。
第二个post方法带一个MailPost接口类的参数,它实际调用接口定义的方法calPrice和post将邮件寄出。
下面我们来看一个Show的执行实例,其中带下划线“_”的部分为执行的键盘输入。
例4.14 Show的执行结果。
--------------------
--------------------
当启动Show的运行后,首先依照提示创建三个邮件对象,其中第一个是不可邮寄包裹后两个分别是可邮寄的包裹和汇款。停止添加邮件后顺序显示现有邮件信息,包括邮件号、邮件类别、地址信息、重量/金额以及已付邮资,并提示现有邮件总数。此时我们可依次检查邮件是否可寄出:
输入邮件号“1”,由于此包裹不是可邮寄包裹类,给出报告:邮件不可寄出;
输入邮件号“2”,该邮件是可邮寄包裹,且通过邮资计算已付足,给出报告:邮件可寄出;
输入邮件号“3”,该邮件是可邮寄汇款,但欠缺邮资,给出报告:邮件需补足邮资,然后列出应交邮费与实交邮费比较。
最后输入数字“0”,结束本次执行。
这样我们就完成了对第三节中邮件类的扩充和改进,最终得到的包ch4package中所有类和接口的层次继承关系,如图4.2所示。读者可以对照这个图理清它们的继承和实现关系。
Object
┌─────┼─────┐
↓ ↓ ↓
Mails ShowMails show
┌───┴───┐
↓ ↓
Parcel Remittance
↓ ↓
PostParcel PostRemit
↖ ↗
MailPost
图4.2 包ch4package的类和接口层次
本章小结
在这一章中,我们真正接触到Java的面向对象的机构:类、包和接口,介绍了如何运用它们实现继承、封装、多态和动态绑定经及这种实现的好处。
在下一章中,将介绍Java的另外两个基本而重要的机制:线程(Thread)和异常(Exception),使大家了解Java的同步和出错处理。 |
|