??xml version="1.0" encoding="utf-8" standalone="yes"?>
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import org.apache.poi.hssf.usermodel.HSSFCell;
import org.apache.poi.hssf.usermodel.HSSFCellStyle;
import org.apache.poi.hssf.util.HSSFColor;
import org.apache.poi.hssf.util.Region;
import org.apache.poi.hssf.usermodel.HSSFFont;
import org.apache.poi.hssf.usermodel.HSSFRow;
import org.apache.poi.hssf.usermodel.HSSFSheet;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
HSSFCellStylecM表一U单元格样式。可以通过q些cL讄单元格的Ҏ(gu)样式、背景颜艌Ӏ字体、水q_垂直方式的对齐?br>?
HSSFWorkbook workbook = new HSSFWorkbook(); //建立一个工作薄
HSSFCellStyle titleStyle=workbook.createCellStyle(); //在工作薄的基上徏立一个样?br> titleStyle.setBorderBottom(HSSFCellStyle.BORDER_DOUBLE); //讄Ҏ(gu)样式
titleStyle.setBorderLeft((short)1); //左边?br> titleStyle.setBorderRight((short)1); //双?br> titleStyle.setBorderTop(HSSFCellStyle.BORDER_DOUBLE); //边?br> titleStyle.setFillForegroundColor(HSSFColor.LIGHT_ORANGE.index); //填充的背景颜?br> titleStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND); //填充图案
假设什么定义了(jin)一个样式,惛_填充W一个单元格的时候填充红Q第二格单元格填充蓝艌Ӏ?br>如果:
HSSFCellStyle cellStyle = workbook.createCellStyle(); //创徏一个样?/font>
cellStyle.setFillForegroundColor(HSSFColor.RED.index); //讄颜色为红?br> cellStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
HSSFCell cell1 = row.createCell((short)1); //l单元格cell1填充U色
cell1.setCellStyle(cellStyle);
? cellStyle.setFillForegroundColor(HSSFColor.BLUE.index); //讄颜色?br>
HSSFCell cell2 = row.createCell((short)2); //l单元格cell2填充蓝色
cell2.setCellStyle(cellStyle);
q个时候会(x)出现的现象是单元格cell1和cell2都变成了(jin)蓝色。遇到这U情况,要预先定义两U不同的单元格样式?/font>
当一个EXCEL文g同时需要很多大同小异的单元格样式时Q这样一一定义很麻?ch)。POI HSSF提供?jin)一个HSSFCellUtilc(在org.apache.poi. hssf.usermodel.contrib包)(j)Q里面有几个Ҏ(gu)可以l过HSSFCellStyle直接讑֮单元格的样式Q但q几个方法会(x)抛出NestableException?nbsp; 常,要处理这个异常,需要引用Apache的几个Common包:(x)
commons-beanutils.jar
commons-beanutils-bean-collections.jar
commons-beanutils-core.jar
commons-lang.jar
commons-logging-api.jar
以下是其他各U情늚处理Q?br>1、中文处理:(x)
要在通过POI生成的EXCEL中正常显CZ文,需要ؓ(f)单元D|编码:(x)
cell.setEncoding(HSSFCell.ENCODING_UTF_16);
cell.setCellValue("部门");
2、合q单元格Q?br>HSSFSheet.addMergedRegion(new Region())Ҏ(gu)可以合ƈ单元|Region()中的一个构造函数含有四个参敎ͼ分别代表起始行、v始列、结?nbsp; 行、结束列Q?br> sheet.addMergedRegion(new Region(initRow, (short)(initCol-2), initRow + lists.size() - 1, (short)(initCol-2)));
3、公式的处理Q?br>HSSFCell.setCellFormula()Ҏ(gu)用来在EXCEL单元g写入公式?br> cell = row.createCell((short)(dataFlag));
cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
cell.setCellFormula("SUM(" + getColLetter(initCol) + (listFlag+1) +":" + getColLetter(dataFlag-1) + (listFlag+1) + ")");
cell.setCellStyle(nameStyle);
4、链接的处理Q?br>在POI中往单元g写链接,是用HYPERLINK函数搞定的?br>HYPERLINK函数包含两个参数Q第一个参数是指向的URL地址Q第二个参数是显C字丌Ӏ?br> cell = row.createCell((short)(dataFlag));
cell.setCellType(HSSFCell.CELL_TYPE_FORMULA);
cell.setCellFormula("HYPERLINK(\"http://www.xxxxx.com/xxx.jsp?id=1\",\"homepage\")");
cell.setCellStyle(linkStyle);
Z(jin)佉K接效果更好,我们可以l链接所在单元格定义一U样式,佉K接显CZؓ(f)有下划线的蓝色字Ԍ(x)
HSSFCellStyle linkStyle = workbook.createCellStyle();
linkStyle.setBorderBottom((short)1);
linkStyle.setBorderLeft((short)1);
linkStyle.setBorderRight((short)1);
linkStyle.setBorderTop((short)1);
linkStyle.setFillForegroundColor(HSSFColor.SKY_BLUE.index);
linkStyle.setFillPattern(HSSFCellStyle.SOLID_FOREGROUND);
HSSFFont font = workbook.createFont();
font.setFontName(HSSFFont.FONT_ARIAL);
font.setUnderline((byte)1);
font.setColor(HSSFColor.BLUE.index);
linkStyle.setFont(font);
关于代码对应的颜色如下:(x)
package com.zhj.tools;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.Properties;
/**
* 文g名:(x)GetProperty.java
* 描述Q?取得当前pȝ变量的程序?br>* java中的System.getProperty只是针对JVM来的Q如果要取得pȝ环境变量Q还要用到系l相关的函数。本E序先从JVM中取Key对应的ValueQ如果取不到再取pȝ环境变量
* 作者:(x) v?br>*/
public class GetProperty {
/**
* @param args
* @throws IOException
*/
public static void main(String[] args) throws IOException {
// TODO Auto-generated method stub
String key=null;
if (args.length>0) key=args[0];
String s=getProperty(key);
System.out.println(s);
}
public static String getProperty(String key) throws IOException{
String value=null;
Properties pp = null;
if (key == null || key.length()<1) {
pp = System.getProperties();
System.out.println("未指定keyQ现列出所有JVM环境变量Q?);
pp.list(System.out);
value="未指定keyQ上面是所有JVM环境变量Q?;
return value;
} else {
String s = null;
value = System.getProperty(key);
if (s == null) {
String OS = System.getProperty("os.name").toLowerCase();
Process p = null;
if (OS.indexOf("windows") > -1) {
p = Runtime.getRuntime().exec("cmd /c set"); // Windowspd
} else if (OS.indexOf("linux") > -1 || OS.indexOf("aix") > -1
|| OS.indexOf("unix") > -1) {
p = Runtime.getRuntime().exec("/bin/sh -c set"); // Unixpd
}
BufferedReader br = new BufferedReader(new InputStreamReader(p
.getInputStream()));
String line;
while ((line = br.readLine()) != null) {
int i = line.indexOf("=");
if (i > -1) {
if(key.equalsIgnoreCase(line.substring(0, i))){
value = line.substring(i + 1);
break;
}
}
}
}
}
return value;
}
}
标题 |
4.1 Java的类
4.1.1 cȝ声明
Java是一U很典型的面向对象的E序设计语言。在面向对象的语a中,世界被看成独立的对象集合Q相互间通过消息来通信。因而这U语a以数据对象ؓ(f)中心(j)Q而不以处理对象的代码Z?j)?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java中的cd数据和有关的操作装在一P描述一l具有相同类型的对象Q作为构{程序的基本单位?br /> cd明定义的格式为:(x)
[cM饰符] classc?/b>?[extends 父类名][implements 接口名]
其中cM饰符用于指明cȝ性质Q可~省。接下来的关键字class指示定义的类的名Uͼcd最好是唯一的。“extends 父类名”通过指出所定义的类的父cdU来表明c间的承关p,当缺省时意味着所定义cMؓ(f)Objectcȝ子类。“implements 接口名”用来指出定义的cd现的接口名称。一个类可以同时实现多个接口。类体则包括一pd数据变量和成员方法的定义声明。下面是一些略ȝ体的cd义例子:(x)
public class WelcomeApp
public class Welcome extends java.applet.Applet
public Car extends Automobile implements Runable
其中前两个类是我们在上一章的CZ中定义的。第三个cL汽车类CarQ它的父cL交通工L(fng)AutomobileQ它q实C(jin)接口Runnable?br /> cM饰符是用以指明类的性质的关键字。基本的cM饰符有三个:(x)
publicQabstract和final
■public
如果一个类被声明ؓ(f)publicQ那么与它不在同一个包中的cM可以通过引用它所在的包来使用q个c;否则q个cd只能被同一个包中的cM用?br /> ■abstract
如果一个类被声明ؓ(f)abstractQ那么它是一个抽象的c,不能被实例化生成自己的对象,通常只是定义?jin)它的子cd有的一些变量和Ҏ(gu)供承用。被声明为abstract的抽象类往往包含有被声明为abstract的抽象方法,q些Ҏ(gu)由它的非抽象子类完成实现l节?br /> ■final
如果一个类被声明ؓ(f)finalQ意味着它不能再z出新的子c,不能作ؓ(f)父类被ѝ因此一个类不能既被声明为abstract的,又被声明为final的?br /> l承是面向对象程序设计中一个强有力的工P它允许在已存在的cȝ基础上创建新的类。新创徏的类UCؓ(f)其基cȝ子类Q基cȝ为其子类的父cR子cȝ对象除了(jin)h新定义的属性和Ҏ(gu)外,q自动具有其父类定义的部分或全部属性方法。这L(fng)序员可以在子cM重用父类中已定义好的变量和方法,只需对子cM不同于父cL新添加的部分重新定义Q这样就节省?jin)大量的旉、空间和_֊?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java在类声明中?br /> extends 父类?br />的方式定义承关pR如果不明显地写出承的父类名,则缺省地认ؓ(f)所声明的类?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java的Objectcȝ一个子cRObjectcLJava中所有的cȝ先cR我们可以把q种cȝ承关pL象ؓ(f)一倒置的类家族?wi),Objectcd是这|(wi)的根?/p>
4.1.2 cȝl成
我们已经知道cL代表对象的,而每一个对象L特定的状态和行ؓ(f)Q在cM分别用变量数据和在数据上可进行的操作表示q些状态和行ؓ(f)。因此类的组成成分是变量和方法。变量和Ҏ(gu)的声明格式如下:(x)
[变量修饰W] 数据cd 变量名[=初值] ;
[Ҏ(gu)修饰W] q回值类型 Ҏ(gu)?参数?
其中修饰W用来指明变量和Ҏ(gu)的特性。变量可一ơ定义一个或多个Q定义时可以l出初倹{例如:(x)
public int a,b=12;
protected String s="Hot Java";
定义Ҏ(gu)时一定要l出q回值类型和参数表。当没有q回值时Q返回值类型记为void。参数表的Ş式ؓ(f)Q?br /> 参数cd 参数值{Q参数类?参数值}
各参数间以逗号分隔。下面是一些简单的例子Q?br /> public static void main(String args[])
public void paint(Graphics g)
public int area(int length,int width){return length * width;}
其中前两个是我们在第三章已经见过的方法声明,q里略去?jin)具体语句组成的?gu)体。第三个则是一个计长方Ş面积的简单方法,接受整数cd的长度和宽度参数q返回它们的乘积作ؓ(f)l果?br /> 变量和方法修饰符是用来指明特性的关键字,主要有以下几U:(x)
■public
一个类中被声明为public的变量和Ҏ(gu)是“公开”的Q意味着只要能用这个类Q就可以直接存取q个变量的数据,或直接用这个方法?br /> ■protected
一个类中被声明为protected的变量和Ҏ(gu)是“受限”的Q意味着它们仅能被与该类处于同一个包的类?qing)该cȝ子类所直接存取和用?br /> ■private
被声明ؓ(f)private的变量和Ҏ(gu)是“私有”的Q除?jin)声明它们的cdQ不能被M其它的类直接存取和用?br /> 当变量或Ҏ(gu)前不加以上三U修饰符Ӟ被认为取friendly状态,卛_们只能被同一个包中的cȝ接存取和使用。但不存在friendly关键字?br /> ■static
被声明ؓ(f)static的变量和Ҏ(gu)是属于类而不是属于对象的。不这个类产生?jin)多个对象Q它们都׃nq个cd量或cL法。我们可以在不创建类实例对象时直接用类变量和类Ҏ(gu)。一般来_(d)?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java中,引用一个特定的变量或方法的形式是:(x)
对象?变量?br /> 对象?Ҏ(gu)?br />例如Q?br /> int a=rectangle.length;
g.drawString("Welcome to Java World!");
卛_量和Ҏ(gu)是受限于对象的,但声明ؓ(f)static的变量或Ҏ(gu)受限于类Q用Ş式是
cd.变量?br /> cd.Ҏ(gu)?br />例如Q?br /> System.out.println("Welcome to Java World!");
String s=String.valueOf(123);
q里我们q没有创建SystemcLStringcȝ对象Q而直接调用Systemcȝcd量out和StringcȝcL法valueOf。其中valueOfҎ(gu)整形参数{换ؓ(f)Stringcd象。被声明为static的类Ҏ(gu)在用时有两点要特别注意Q?br /> (1)cL法的Ҏ(gu)体中只能使用cM其它同样是static的变量或Ҏ(gu)Q?br /> (2)cL法不能被子类修改或重新定义?br /> ■final
变量或Ҏ(gu)声明为finalQ可以保证它们在使用中不被改变。被声明为final的变量必d声明时给定初|而在以后的引用中只能dQ不可修攏V被声明为final的方法也同样只能使用Q不能重载?br /> ■abstract
q个修饰W仅适用于方法。被声明为abstract的方法不需要实际的Ҏ(gu)体,只要提供Ҏ(gu)原型接口Q即l出Ҏ(gu)的名U、返回值类型和参数表,格式如下Q?br /> abstract q回值类型 Ҏ(gu)?参数?Q?br />定义?jin)abstract抽象Ҏ(gu)的类必须被声明ؓ(f)abstract的抽象类?/p>
4.1.3 构造方法和finalizer
Java中有两个Ҏ(gu)的方法:(x)用于创徏对象的构造方?constructor)和用于撤销对象的方法finalizerQ相当于C++中的构造函数和析构函数。构造方法是生成对象时编译器自动调用的方法,用以l出对象中变量的初倹{构造方法必Mcd名,而且l对不允许有q回|甚至不允总void来标记无q回倹{一个类的构造方法可以有多个Q以不同的参数表区分不同的情形,q是Java多态性的一个体现。下面是一个简单的例子?br /> ?.1 Rectanglecȝ构造方法?br /> class Rectangle{
protected int width;/*cRectangle的两个整型变?/
protected int height;/*分代表长方Ş的长和宽*/
/*下面是类Rectangle的三个构造方?/
/*W一个构造方法,无参敎ͼ~省地给出长和宽*/
Rectangle()
/*W二个构造方法,l出ѝ宽参数*/
Rectangle(int w,int h)
/*W三个构造方法,l出另一个Rectangle作参?/
Rectangle(Rectangle r)
{width=r.width();
height=r.height();
}
/*下面是类Rectangle的另外两个方法,分别为取长和宽的?/
public int width()
{return width;}
public int height()
{return height;}
}
class Test{
Rectangle r1=new Rectangle();/*调用W一个构造方?/
Rectangle r2=new Rectangle(12,20);/*调用W二个构造方?/
Rectangle r3=new Rectangle(r1);/*调用W三个构造方?/
}
在这个例子中Rectangle有三个构造方法,它们的名字相同,参数不同因而采用的调用形式也不同。第一个构造方法不需要Q何参敎ͼ调用时系l自动地l出l一的固定的长方形的宽和?q里我们讑֮?0?0)。第二个构造方法需要两个整形参敎ͼҎ(gu)用户l出的长方Ş的宽和高创徏长方形对象。第三个构造方法需要一个长方Ş参数Q创建出与这个长方Şh同样的宽和高的长方Ş对象。在RectanglecMQwidth和height都是protected的,不宜直接存取。ؓ(f)?jin)用方便,我们定义出width()和height()Ҏ(gu)来获得一个特定长方Ş的宽和高Q再取得的数g递给新创建的对象。像q样在一cM有两个或两个以上同名Ҏ(gu)的现象叫OverloadingQ是多态的一U表现。这样同名方法应该有且必L不同的参数表Q调用时~译pȝ是Ҏ(gu)参数的匹配情况,包括个数和类型,来决定实际用哪一个方法的。如果两同名Ҏ(gu)的参数表也相同,?x)造成hQ编译时得到出错信息:(x)
Duplicate method declaration
(重复的方法声?
Z(jin)实际创徏出对象,我们要用new。系l执行遇到newQ才Ҏ(gu)new后面跟随的构造方法名和参数表Q选择合适的构造方式,分配内存Q创建对象ƈ初始化。一个类若没有显C地定义构造方法,使用new时将调用它的父类的构造方法,q种上溯可一直到达Objectc,而Objectcȝ构造方法是语言预先定义好的?br /> 相对于构造方法,在对象被撤销时调用的Ҏ(gu)是finalizer。对所有的c,它的原始定义形式都是一L(fng)Q?br /> void finalize();
没有q回|而且没有M参数。一般来_(d)׃Java的内存管理是ql自动完成,通常不需要我们重写这个方法,而让它自然而然C父类(最l也是从Objectc?l承。只有当某些资源需要自动归q时Q才需要将q一Ҏ(gu)重写?/p>
4.1.4 重写(Overriding)和重?Overloading)
Ҏ(gu)的重写Overriding和重载Overloading?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java多态性的不同表现。前者是父类与子cM间多态性的一U表玎ͼ后者是一个类中多态性的一U表现。如果在子类中定义某Ҏ(gu)与其父类有相同的名称和参敎ͼ我们说该Ҏ(gu)被重?Overriding)。子cȝ对象使用q个Ҏ(gu)Ӟ调用子cM的定义,对它而言Q父cM的定义如同被“屏蔽”了(jin)。如果在一个类中定义了(jin)多个同名的方法,它们或有不同的参C数或有不同的参数cdQ则UCؓ(f)Ҏ(gu)的重?Overloading)。这在例4.1中已l可以看到。下面再l出两个单的例子Q分别显COverriding和Overloading?br /> ?.2 Overriding的例C?br /> class Father{
void speak(){
System.out.println("I am Father!");//父类定义的speakҎ(gu)
}
}
class Son extends Father{
void speak(){
System.out.println("I am Son!");//子类重写的speakҎ(gu)
}
}
public class Check{
public static void main(String args[]){
Son x=new Son();
x.speak();//调用子类的speakҎ(gu)
}
}
//output of class Check!
I am Son!
从这个例子我们可以看刎ͼcSon中的speak()Ҏ(gu)重写?jin)其父类Father中一模一L(fng)Ҏ(gu)Q而它的对象x调用speak()Ҏ(gu)的结果是与Son中定义致的?br /> ?.3 Overloading例示?br /> class Father{
void speak(){ //无参的speakҎ(gu)
System.out.println("I am Father.");
}
void speak (String s){ //有参的speakҎ(gu)
System.out.println("I like"+s+".");
}
}
public class Check{
public static void main(String args[]){
Father x=new Father();
x.speak();//调用无参的speakҎ(gu)
x.speak("music");//调用有参的speakҎ(gu)
}
}
//out put of class Check
I am Father
I like music.
q个例子中类的Father定义?jin)两个speakҎ(gu)Q在cCheck中又两次调用Q一ơ无参,一ơ有参,打印Z行不同的字符丌Ӏ注?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java在打印字W串Ӟ字符串间的连接用W号?”来完成?/p>
Overriding是父cM子类之间多态性的一U表玎ͼOverloading是一个类中多态性的一U表现?/p>
4.1.5 几个Ҏ(gu)的变量:(x)nullQthis和super
Java中有三个Ҏ(gu)的变量:(x)null,this和superQ这三个变量是所有的c都可以使用的,用来指示一些特定的对象?br /> null相当于“空”,可以用来代指M对象Q但没有实例。如
Rectangle r=null;
创徏?jin)一个Rectangle的变量rQ但q没有一个Rectangle的实例对象由r来代表。r如同一个可攄Rectangle的盒子,只是q个盒子现在是空的?br /> this用以指代一个对象自w。它的作用主要是自p个对象作为参敎ͼ传送给别的对象中的Ҏ(gu)。它的用Ş式是q样的:(x)
class Painter{
...
void drawing(Father y){
...
}
}
class Father{
...
void draw(Painter x)
{...
x.drawing(this);/*自w传递给x的drawingҎ(gu)*/
...
}
}
class Test{
...
Father f=new Father();
Painter p=new Painter();
f.draw(p);
...
}
例中调用FathercȝdrawҎ(gu)Ӟ使用语句
f.draw(p);
又F(tun)athercM定义drawҎ(gu)时以this为参数调用了(jin)cPainter的drawingҎ(gu)Q?br /> x.drawing(this);
因而实际上调用?jin)Paintercd象p的drawingҎ(gu)Q而将Fathercd象f作ؓ(f)参数传递给drawingҎ(gu).
super用来取用父类中的Ҏ(gu)和变量数据。它的用法如在下面的例子中所C?br /> ?.4在类中用super的例C?br /> /* Check.java */
class Father{
void speak(){
System.out.println("I am Father.");
}
void speak(String s){
System.out.println("I like "+s+".");
}
}
class Son extends Father{
void speak(){
System.out.println("My father says.");
super.speak();//相当于调用Fathercȝspeak()Ҏ(gu)
super.speak("hunting");
//相当于调用Fathercȝspeak(String s)Ҏ(gu)
}
}
class Check{
public static void main(String args[]){
Son s=new Son();
s.speak();
}
}
//Check.java的执行结果:(x)
My father says:
I am Fater.
I like hunting.
在这个例子中Q类Son的speak()Ҏ(gu)语句
super.speak();
super.speak("hunting");
实际调用?jin)Son的父cFather中的speak()和speak(String s)Ҏ(gu)Q以实现执行l果后两行的输出。用父cȝ变量形式也很cM?br /> super.变量?br /> super和this的另一个重要用途是用在构造方法中。当一个类中不止一个构造方法时Q可以用this在一个构造方法中调用中一个构造方法。若惌用父cȝ构造函敎ͼ则直接用super。例如我们可?j)如下定义?.1中类Rectangle的子cColorRectangle:
public class ColorRectaqngle extends Rectangle{
int color;
ColorRectangle(int w,int h,int c){
super(w,h);
color=c;
}
...
}
与父cRectangle相比Q类ColorRectangle增加?jin)color成员变量代表长方形的颜色。在它的构造方法中Q用语句
super(w,h);
调用?jin)类Rectangle的构造方?br /> Rectangle(int w,int h);
讑֮长方形的长和宽,然后只需讑֮长方形的颜色Q?br /> color=c;
q样大大提高?sh)(jin)代码的重用性?br />
4.2 Java的包
?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java中,包的概念和目的都与其它语a的函数库非常cMQ所不同的只是其中封装的是一l类。ؓ(f)?jin)开发和重用的方便,我们可以写好的E序cL理成一个个E序包?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java自n提供?1个预先设定好的包Q下面列出其中主要的几个Q其余读者参?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java的APIQ?br /> java.lang 提供基本数据cd?qing)操?br /> java.util 提供高数据cd?qing)操?br /> java.io 提供输入/输出控?br /> java.awt 提供囑ŞH口界面控制
java.awt.event 提供H口事g处理
java.net 提供支持Internet协议的功?br /> java.applet 提供实现览器环境中Applet的有关类和方?br /> java.sql 提供与数据库q接的接?br /> java.rmi 提供q程q接与蝲入的支持
java.security 提供安全性方面的有关支持
我们可以引用q些包,也可以创q包?/p>
4.2.1 包的声明
Z(jin)声明一个包Q首先必d立一个相应的目录l构Q子目录名与包名一致。然后在需要放入该包的cL件开头声明包QŞ式ؓ(f)Q?br /> package 包名Q?br />q样q个cL件中定义的所有类都被装入C所希望的包中。例?br /> package Family;
class Father{
...//cFather装入包Family
}
class Son{
...//cSon装入包Family
}
class Daughter{
... //cDaughter装入包Family
}
不同的程序文件内的类也可以同属于一个包Q只要在q些E序文g前都加上同一个包的说明即可。譬如:(x)
//文g Cat.java
package Animals;
class Cat{/*类Cat攑օ包Animals?;
...
}
//文gDog.java
package Animals;
class Dog{ /*类Dog攑օ包Animals?/
...
}
4.2.2 包的使用
?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java中,Z(jin)装蝲使用已编译好的包Q通常可用以下三U方法:(x)
(1) 在要引用的类名前带上包名作ؓ(f)修饰W。如Q?br /> Animals.Cat cat=new Animals.Cat();
其中Animals是包名,Cat是包中的c,cat是类的对象?br /> (2)在文件开头用import引用包中的类。如Q?br /> import Animals.Cat;
class Check{
Cat cat=new Cat();
}
同样Animals是包名,Cat是包中的c,cat是创建的Catcd象?br /> (3)在文件前使用import引用整个包。如Q?br /> import Animals.*;
class Check{
Cat cat=new Cat();
Dog dog=new Dog();
...
}
Animals整个包被引入QCat和Dog为包中的c,cat和dog为对应类的对象?br /> 在用包Ӟ可以用点??表示出包所在的层次l构Q如我们l常使用?br /> import java.io.*;
import java.applet.*;
实际是引入了(jin)/java/io/?java/applet/q样的目录结构下的所有内宏V需要指出的是,java.langq个包无需昑ּ地引用,它L被编译器自动调入的。用包时还要特别注意系lclasspath路径的设|情况,它需要将包名对应目录的父目录包含在classpath路径中,否则~译时会(x)出错Q提C用L(fng)译器找不到指定的cR?/p>
4.3 一个邮件类(Mails)的例?/p>
下面我们l出一个较大的例子Q让读者在实例中进一步熟(zhn)?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java的类和包?br /> q里所有的c都攑֜包ch4package中,先定义出一个虚基类MailsQ然后派生出它的两个子类Parcel(包裹)和Remittance(汇款)。Showcȝ于实际执行,允许用户创徏自己的邮Ӟ然后昄出所有的邮g信息。ؓ(f)?jin)方便地存取邮gQ还定义?jin)类ShowMails。接下来我们逐一介绍q经些类?br /> ?.5 cMailsE序文g?br /> 1Qpackage ch4package;
2: public abstract class Mails{
3: protected String fromAddress;
4: protected String toAddress;
5: public abstract void showMe();
6: }
cMails是一个虚c,不能产生自己的实例对象,而只是描qC(jin)邮g最基本的特性。类文g的开头首先用
package cha4package;
表明MailscL放于ch4packageq个包里的。然后程序第二行为Mails的类声明?br /> public abstract class Mails
用修饰符abstract指出q是个虚cR第三至W四行MailscM定义?jin)两个变量?x)
protected String fromAddress;
protected String toAddress;
fromAddress和toAddress ,分别代表邮g的寄出地址和送往地址Q都是protectedcd的,q样cha4package包外的类不能直接引用Q保证了(jin)信息的隐藏。第五行Mailscd义了(jin)Ҏ(gu)
showMe()Q用于显CZ个邮件自w的有在信息Q?br /> public abstract voi showMe();
声明时以abstract修饰Q意味着q是一个抽象方法,只给出原型,具体实现要由Mailscȝ非虚子类通过Overriding完成?br /> 接下来是Mails的两个非虚子cR?br /> ?.6 cParcel和类RemittanceE序文g?br /> //Parcel.java
1: package ch4package;
2: public class Parcel extends Mails{//邮gcȝ子类Parcelc?br /> 3: protected int weight;
4: Parcel(String address1,String address2,int w){//构造方?br /> 5: fromAddress=address1;
6: toAddress=address2;
7: weight=w;
8: }
9: public void showMe(){
10: System.out.print("Parcel:");
11: System.out.println("\tFrom:"+fromAddress+"\tTo:"+toAddress);
12: System.out.println("\tWeigth:"+weight+"g");}
13: }
//Remittance.java
1: package ch4package;
2: public class Remittance extends Mails{//邮gcȝ子类Remittance
3: protected int money;
4: Remittance(String address1,String address2,int m){//构造方?br /> 5: fromAddress=address1;
6: toAddress=address2;
7: money=m;
8: }
9: public void showMe(){//昄邮g信息
10: System.out.println("Remittance:");
11: System.out.println("\tFrom:"+fromAddress+"\tTo:"+toAddress);
12: System.out.println("\tMoney:"+money+" Yuan");
13: }
14:}
q里是邮件的两个子类Q包裹Parcel和汇ƾRemittance。以cParcelZ详细说明。首先在E序开头写出:(x)
package ch4package;
一斚w类Parcel装入包ch4packageQ另一斚w方便cParcel使用包ch4package中的其它c,如已定义的MailscR接下来cParcel声明时用
extends Mails
表明自己是Mails的一个子cR在W三行Parcel声明?jin)一个weight变量Q用来代表包裹的重量。加上从父类Mailsl承下来的变量fromAddress和toAddressQ类Parcel一共有三个成员变量Q?br /> 寄出地址 fromAddressQ寄辑֜址toAddress和重量weight
相对应的Q它的构造方法Parcel也必L三个参数Q分别传递给三个成员变量。构造方法的定义如第四行至第八行所C。由于ParcelcM是虚c,所以必d其中重写完成它的父类Mails中声明的抽象Ҏ(gu)showMe。Parcel的showMe()Ҏ(gu)仅仅是将自己的邮件类型和三个变量的信息在屏幕上显C出来?br /> cRemittance与Parcel非常怼Q只是它定义的变量ؓ(f)moneyQ用来代表汇Ƅ金额。它也必d体完成方法showMe?br /> 下面我们看到的是用于存取邮g的类ShowMails?br /> ?.7 cShowMailsE序文g?br /> 1: package ch4package;
2: import java.lang.*;
3: public class ShowMails{
4: protected Mails showList[];//邮g数组序列
5: protected static final int maxMails=50;//最大邮件个?br /> 6: protected int numMails;//当前邮g个数
7: ShowMails(){
8: showList=new Mails[maxMails];
9: numMails=0;
10: }
11: public void putMails(Mails mail){
12: if(numMails<maxMails){
13: showList[numMails]=mail;//加入邮g
14: numMails++;//修改计数
15: }
16: }
17: public Mails getMails(int index){//获取邮g
18: if((0<=index)&&(index<numMails)) return showList[index];
19: else return null;
20: }
21: public void showAll(){//展示邮g
22: if(numMails>0)
23: for (int i=0;i<numMails;i++){
24: System.out.print("Mail NO"+(i+1)+":");//邮g序号
25: showList[i].showMe();//邮g具体信息
26: }
27: else
28: System.out.println("No mails.");
29: }
30: public int mailnum(){
31: return numMails;
32: }
33:}
E序W四行至W六行类ShowMails定义?jin)三个成员变量?x)
showList[],maxMails和numMails
变量showList[]是类Mails的一个数l。但׃Mails本n是个虚类Q因而showList[]的元素不可能是Mails的对象,它实际上是用来存放Mails的两个子cParcel和Remittance的对象的。一般说来,一个被声明为类A的的变量Qd以被赋gؓ(f)McA的子cȝ实例对象。这与父子类之间的类型{换的原则是一致的Q父cd子类的{换可以隐式地自动q行Q而子cd父类的{换则需要显式地加以说明?br /> 变量maxMails用来指出showList[]中最多可?U的邮g敎ͼ它对ShowMails的所有对象都应是固定且一致的。因此它被声明ؓ(f)tatatic和final的,为所有对象共享且不可更改。变量numMails则用来作为showList[]中实际邮件个数的计数?br /> 对应ShowMails的三个成员变量,我们在ShowMails()构造方法中只需做两件事Q实际创建类mails的数lshowList[]Q然后将邮g计数numMails|零?br /> W?1行开始的Ҏ(gu)putMails和第17行开始的Ҏ(gu)getMails分别完成对showList[]中邮件的存取。第30行的mailnumҎ(gu)则返回当时的邮g计数倹{putMailsҎ(gu)接受一个邮件类参数Qƈ把它加入到当前邮件序列的末尾。getMailsҎ(gu)接受一个整型参C为邮件序PҎ(gu)该序h出当前邮件序列中对应邮gq回。当l定的邮件号index不在有效范围Ӟ以据该序h出当前邮件序列中对应邮gq回。当l定的邮件号index不在有效范围Ӟ?br /> return null;(19?
q回一个定倹{这一句看上去q没有完成什么实质性的工作Q但如果省略则编译时?x)出错。因为getMailsҎ(gu)的返回值已声明为Mailsc,q就要求在Q何情况下都返回一个符合这一要求的倹{而空变量null可与Mcd匚wQ恰好能适合q样的要求?br /> W?1行的Ҏ(gu)showAll昄showList[]中所有邮件的信息。每一邮g首先昄自己的邮件号。因为showList[]数组的下标从0开始,Z(jin)W合Z的日怹(fn)惯,每一个下标加1后再作ؓ(f)邮g可出。各个邮件的昄是调用邮件的showMe()Ҏ(gu)来实现的。因为showMe()Ҏ(gu)已经在虚cMails中定义了(jin)Q所以不showList[]中的实际元素是Parcelq是RemittanceQ编译器总能利地连接调用相应的代码?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java面向对象Ҏ(gu)中的动态绑?Dynamic Binding)Q保证了(jin)无需在编译前定地知道showList[]每一个数l元素的cdQ就能成功地实现q样的链接?br /> 最后给出的cL实际执行的ShoscR?br /> ?.8 cShowE序文g
1: package ch4package;
2: import java.io.*;
3:
4: public class Show{
5: public static ShowMails board=new ShowMails();//邮g库变?br /> 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){//d邮g
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();
//选择邮g各类(包裹或汇?
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("Parce\tWeight:");
26: System.out.flush();
27: int w=getInt();
28: Parcel pa=new Parcel(address1,address2,w);
29: board.putMails(pa);
30: }
31: if('2'==ch){//输入汇款金额
32: System.out.print("Remittance\tMoney:");
33: System.out.flush();
34: int m=getInt();
35: Remittance re=
new Remittance(address1,address2,m);
36: board.putMails(re);
37: }
38: }
39: else finished=true;
40: }
41: System.out.println(" ");
42: board.showAll();//输出所有邮件信?br /> 43: }
//键盘输入获取整数
44: public static int getInt() throws IOException{
45: BufferedReader in= new BufferedReader
(new InputStreamReader(System.in));
46: String st=in.readLine();
47: Integer i=new Integer(st);
48: return i.intValue();
49: }
50:}
׃涉及(qing)交互Q类Show中用C(jin)许多输入输出语句Q我们在E序W?行用
import java.io.*;
引入Java的IO包。这个包装?jin)大量有兌入输出的?gu)Q具体内容将在第七章中详l介l。这里我们只需要弄清楚所用到的输??gu)句的功能?br /> 在输?ZQL可能产生输入输出错误Q?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java反这引v错误都归入IOException(IO异常)因ؓ(f)我们不打在E序中加入对q些异常的处理,所以需要在每个Ҏ(gu)的参数表后用关键字throws“扔出”这些异常,如第6?br /> public static void main(String args[])throws IOException
q样异常发生Ӟ自动中止程序运行ƈq行标准处理。请参看W五章的内容?br /> E序的输入来源是一个BufferedReadercȝ对象inQ它的声明在W8行:(x)
BufferedReader in=new BufferedReader(new InputStreamReader(System.in));
因而具有BufferedReader中定义的所有输入功能?br /> in.readLine()
是读入一行输入,q返回一字符丌Ӏ?br /> charAt(i)
是Stringcȝ一个方法,取得指定字符串的Wi个元素作为字W型q回。这两上Ҏ(gu)边用Q则可取得想要的输入。而在输入前用
System.out.flush();
缓冲清I,以保证输入的正确性?br /> System.out.print
System.out.println
都是输出语句Q不同的只是后者在输出l束后自动换行。类System和getInt()中用到的c都是Interger(注意不是int!)都在Java的lang名中定义Q我们将在第六章详细介绍?br /> 在了(jin)解以上的基本输入输出后,q个E序变得较{了(jin)。ؓ(f)?jin)方便v见,我们不失一般性的Showcȝ所有成员都定义为static的,q样Q类Show׃同志需要特别定义的构造方法了(jin)。在W5行声明的变量board是ShowMailscȝ对象Q用来徏立邮件库Q?br /> public static ShowMails board=new ShowMails();
W?4行开始的getIntҎ(gu)用来从键盘输入获得一个整数。第6行开始的mainҎ(gu)则是E序的主体。它实现的功能是不断询问是否要加入新邮gQ肯定回{时要求选择邮gcdq输入相应信息。据此创建邮件子cd象ƈ加入board中,直至得到不定回答退出。最后显C此时已有的邮g信息。邮件的加入和显C都通过单的
board.pubMails()
board.showAll()
调用ShowMails的方法来实现的,z明?jin)而层ơ清晰。这是面向对象q行数据装和重用的优点所在。要执行cShowQ我们需要将?.5~例4.8的文件依ơ输入、编译。最后用解释?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">java执行cShow。下面给出的是Show的运行结果,其中加下划线“_”的是键盘输入?br /> ?.9 cShowq行l果?br /> D:\java01>java ch4package.Show
Do you want to add mails(Y/N)?n //询问有是否添加邮?/p>
No mails. //昄没有邮g
D:\java01>java ch4package.Show
Do you want to add mails(Y/N)?y//询问有是否添加邮?br /> Address information: //要求输入地址信息
From:NanJing
To:BeiJing
Choose the mail type:1-Parcel 2-Remittance 1//要求选择邮gcd
Parce Weight:100//要求输入包裹重量
Do you want to add mails(Y/N)?y
Address information:
From:ShangHai
To:TianJing
Choose the mail type:1-Parcel 2-Remittance 2
Remittance Money:400//要求输入汇款金额
Do you want to add mails(Y/N)?n
Mail NO1:Parcel://输出所有邮件信?br /> From:NanJing To:BeiJing
Weigth:2g
Mail NO2:Remittance:
From:ShangHai To:TianJing
Money:400 Yuan
D:\java01
4.4 Java的接?/p>
4.4.1 引进接口的目?/b>
Java的接口也是面向对象的一个重要机制。它的引q是Z(jin)实现多承,同时免除C++中的多扉KL(fng)复杂性。前面讲q,抽象cM包含一个或多个抽象Ҏ(gu)Q该抽象cȝ子类必须实现q些抽象Ҏ(gu)。接口类g抽象c,只是接口中的所有方法都是抽象的。这些方法由实现q一接口的不同类具体完成。在使用中,接口cȝ变量可用来代表Q何实C(jin)该接口的cȝ对象。这q当于把类Ҏ(gu)其实现的功能来分别代表,而不必顾虑它所在的cȝ承层ơ。这样可以最大限度地利用动态绑定,隐藏实现l节。接口还可以用来实现不同cM间的帔R׃n?br /> Z(jin)说明接口的作用,我们不妨假设有一pd的图形类Q其中一部分在图形中加入?jin)文字,成?f)可编辑的Q它们应当支持最普遍的编辑功能:(x)
cutQcopyQpaste和changeFont
这些方法的原型l一l合在一个EditShape接口中,可以保证方法名的规范统一和用的方便。我们画?gu)个假想的cd接口的承关pdQ可以更直观C(jin)解?/p>
Object
?br /> Shape
┌────────────┼─────────────?br /> ↓ ↓ ?br /> Circle Rectangle Triangle
↙ ↘ ↙ ↘ ↙ ?br /> PaintCircle TextCircle PaintRectangle TextRectangle PaintTriangle TextTrangle
↑ ↑ ?br /> └───────────┼───────────────?br /> EditShape
?.1 Shape ?EditShape
以图中类Circle的两个子cMؓ(f)例。类PaintCircle未实现EditShape接口Q不支持上述~辑功能。而类TextCircle既是Cricle的子c,又实C(jin)EditShape接口Q因而不但具有Circlecȝ囑ŞԌ又支持EditShape定义的编辑功能。而在TextCircleQTextRectangle和TextTriangle中,支持q些~辑功能的方法是同名同参?与EditShape的定义一?Q这又提供了(jin)使用上的方便?/p>
4.4.2 接口的声明和使用
Java的接口类g抽象c,因而它的声明也和抽象类cMQ只定义?jin)类中方法的原型Q而没有直接定义方法的内容。它的声明格式ؓ(f)Q?br /> [接口修饰W] interface 接口?[extends 父类名]
接口修饰W可以是public或abstractQ其中abstract~省时也有效。public的含义与cM饰符是一致的。要注意的是一个编译单元,即一?java文g中最多只能有一个public的类或接口,当存在public的类或接口时Q编译单必须与这个类或接口同名?br /> 被声明的变量L被视为static和final的,因而必d声明时给定初倹{被声明的方法Labstract的,abstarct~省也有效。与抽象cMP接口不需要构造方法。接口的l承与ؓ(f)是一L(fng)Q当然一个接口的父类也必L接口。下面是一个接口的例子Q?br /> interface EditShape{
void cut();
void copy();
void paste();
void changeFont();
}
在用时Qؓ(f)?jin)将某个接口实现Q必M用关键字implements。格式是q样的:(x)
[cM饰符] class cd [extends 父类名] [implements 接口名表]
其中Q接口名表可包括多个接口名称Q各接口间用逗号分隔。“实?implements)“了(jin)一个接口的非抽象类必须写出实现接口中定义的Ҏ(gu)的具体代码,同时可以d使用接口中定义的M变量?br /> ?.10 接口的实?br /> class TextCircle extends Circle implements EditShape
{...
void cut()
void copy()
void paste()
void changeFont
...
}
4.4.3 多?/b>
?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java中,cM间只允许单承,但我们可以把一个类实现的接口类也看作这个类的父cR类从它实现的接口那里“扎(k)了(jin)变量和方法,管q些变量是静(rn)态常量,q些Ҏ(gu)是未实现的原型。如果一个类实现的接口类不止一个,那么所有这些接口类都被视ؓ(f)它的“父cZ。这P实现?jin)一个或多个接口的类q当于是从两个(加上该类原有意义上的父类)或两个以上的cL生出来的?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java的多l承正是建立在这U意义之上。通过接口的承,相当于只选择?jin)一部分需要的特征汇集在接口中׃同的cd享ƈl承下去Q而不必通过父子c间的承关pd所有的Ҏ(gu)和变量全部传递给子类。所以我们又可以?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java的这U多l承UCؓ(f)“有选择的多l承”。这U多l承与一般的多承相比,更ؓ(f)_Q复杂度也随之大大降低?br /> 在多l承Ӟ一个子cd能会(x)从它的不同父c那里承到同名的不同变量或Ҏ(gu)Q这往往?x)引起两义性问题,即不知道子类中这L(fng)变量或方法究竟是l承?jin)哪一个父cȝ版本Q在Java中,Z(jin)防止出现q样的两义性问题,规定不允怸个子cȝ承的父类和实现的接口cM定义同名的不同变量,否则~译该子cL出错,无法通过。而对于方法,׃接口cM定义的Labstract的方法原型,而没有实际代码,所以不?x)出现类似的两义性问题。相反,怼(x)存在q样的情况:(x)当接口类中要求实现的Ҏ(gu)子类没有实现Q而子cȝ父类中定义有同名Ҏ(gu)Ӟ~译器将子类从父l承的该Ҏ(gu)视ؓ(f)Ҏ(gu)口的的实现。这L(fng)l承和实现都被认为是合法的?/p>
4.5 实现?jin)接口的邮gcM?/b>
q一节我们将4.3节邮件类的例子加以改q和扩展Q加入有x(chng)口的内容Q以说明接口和多l承的概c(din)?br /> 首先定义一个名为MailPost的接口,其中没有定义变量Q而是l出两个有关邮寄Ҏ(gu)原型?br /> calPrice()计算邮费q以点数Ş式返回;
post()完成邮寄?br /> ?.11 接口MailPost?br /> //MailPost.java
package ch4package;
public interface MailPost{
public float claPrice();
public void post();
}
接下来在包裹Parcel和汇ƾRemittance的基上分别派生出可邮寄的包裹和汇ƾ:(x)PostParcel和PostRemit两个子类?br /> ?.12 子类PostParcel和PostRemit?br /> ---------------------------------
//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){
//构造方?br />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(){//昄邮g信息
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){
//构造方?br />super(address1,address2,m);
postage=p;
postable=false;
posted=false;
}
public float calPrice(){//计算邮资
float price=cealPrice();
postable=(price<=postage);
posted=true;
}
public void showMe(){//昄邮g信息
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");
}
}
}
}
---------------------------------
q两个类都实C(jin)接口MailPost。由于两个类非常怼Q我们仍焉点讲解其中一个:(x)cPostParce?br /> PostParcel仍是包ch4package中的一员,它是cParcel的子c?extends Parcel)Q又实现?jin)接口MailPost(implements MailPost)Q?br /> public class PostParcel extends Parcel implements MailPost
在Parcel的基上,它新增加?jin)三个变量?x)
postageQpostedQpostable
其中整型的postage用来记录邮寄人提供的邮资Q布?yu)(dng)型的posted和postable分别用来记录是否被尝试邮寄过以及(qing)邮寄是束成功。在PostParcel的构造方法中Q第9行语?br /> super(address1,address2,w);
调用?jin)它的父cParcel的构造方法,讑֮它从Parcel中承的变量寄出地址、寄辑֜址和重量的初倹{这是我们在前面提到过的super变量在构造方法中的用途:(x)调用父类的相应构造方法。这样做的一个好处是可以重用父类的代码,然后PostParcel只需讑֮邮资Qƈposted和postable初值都|ؓ(f)false?br /> PostParcel和PostRemit都实C(jin)接口MailPostQ国而在它们的定义中Q都必须l出Ҏ(gu)calPrice()和post()的具体实现。在PostParcel中,Z(jin)单v见,邮费只是Ҏ(gu)重量每克收到0.05元,而不考虑寄达的距,如语句第15行:(x)
return ((float)0.05*weight);
在post()Ҏ(gu)中,计所得邮资与瑞有邮费加以比较Q若邮费已够postable设ؓ(f)trueQ包裹可邮寄Q否则postable为falseQ包裹不可邮寄。无论postable取值如何,都已试图邮寄Q所以将posted|ؓ(f)true。处理过E见W?8行至20行?br /> 最后一个方法是showMe()。在q里QPostParcel重写(Overriding)?jin)它的父cParcel中的同名Ҏ(gu)。当包裹未被试N寄过Q则在基本信息后附加有关的邮寄信息,若未邮寄成功Q给出所需最Ҏ(gu)C?br /> PostRemitcȝ基本构成与PostParcel是一致的Q读者可以自p着L它的源文件?br /> 在包ch4package中,cMailsQParcelQRemittance以及(qing)ShowMails都无需改动Q只有最后的可执行类Show需要相应的修改。它的源E序如下?br /> ?.13 可执行类ShowE序文g?br /> -------------------------
//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){//d邮g
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();
//选择邮gU类
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();
//是否寄出邮g
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();
//可邮寄包?br />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();
//可邮寄汇?br />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();//昄邮g信息
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;
//(g)查邮寄情?br />while(!end){
System.out.print("\nInput the mail NO you want to check the
result(?退?:");
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();
}
}
-------------------------
与第三节?.8中类的Show相比Q改动后的Show的mainҎ(gu)增加?jin)询问是否要邮件设为可邮寄cd的功能以?qing)相应的处理D,q调用Post()Ҏ(gu)邮寄邮gq给出邮寄情况说明。类Show定义?jin)两个postҎ(gu)来实惠邮寄。这两个Ҏ(gu)虽同名,但参C同,完成的功能也大相径庭?br /> W?2行至92行的W一个postҎ(gu)没有参数。它首先l出现有邮g数量Q然后根据输入的邮g号通过ShowMails的getMailsҎ(gu)取得邮gQ再调用W二个postҎ(gu)实际邮件寄出;当输入的邮g号ؓ(f)零时l束。在调用W二个postҎ(gu)Ӟ需要将邮g昑ּ转换为接口类MailPost:
83:Mails obj=bord.getMails(i-1);
84:post((MailPost)obj);
因ؓ(f)PostParcel和PostRemit都实C(jin)接口MailPostQ都支持q样的{换,可以通过UŞ式从功能上将它们l一h。如果该邮g所属的cL有实现接口MailPost ,如类Parcel或类RemittanceQ这L(fng)cd转换׃能实玎ͼ引发类型{换异?ClassCastException)Q不再{去调用postҎ(gu)Q而由catchl构l出“邮件无法被邮寄”的报错信息Q?br /> 86:}catch(ClassCastException ex){
87: System.out.println("Mail is not postable!");}
其中的try-catchl构?b style="COLOR: black; BACKGROUND-COLOR: #ffff66">Java中异常处理的典型l构?br /> W二个postҎ(gu)带一个MailPost接口cȝ参数Q它实际调用接口定义的方法calPrice和post邮件寄出?br /> 下面我们来看一个Show的执行实例,其中带下划线“_”的部分为执行的键盘输入?br /> ?.14 Show的执行结果?br /> --------------------
--------------------
当启动Show的运行后Q首先依照提C创Z个邮件对象,其中W一个是不可邮寄包裹后两个分别是可邮寄的包裹和汇ƾ。停止添加邮件后序昄现有邮g信息Q包括邮件号、邮件类别、地址信息、重量/金额以及(qing)已付邮资Qƈ提示现有邮gL。此时我们可依次(g)查邮件是否可寄出Q?br /> 输入邮g号“1”,׃此包裹不是可邮寄包裹c,l出报告Q邮件不可寄出;
输入邮g号“2”,该邮件是可邮寄包裹,且通过邮资计算已付Il出报告Q邮件可寄出Q?br /> 输入邮g号“3”,该邮件是可邮寄汇ƾ,但欠~邮资,l出报告Q邮仉补邮资Q然后列出应交邮费与实交邮费比较?br /> 最后输入数字“0”,l束本次执行?br /> q样我们完成了(jin)对第三节中邮件类的扩充和改进Q最l得到的包ch4package中所有类和接口的层次l承关系Q如?.2所C。读者可以对照这个图理清它们的承和实现关系?br /> Object
┌─────┼─────?br /> ↓ ↓ ?br /> Mails ShowMails show
┌───┴───?br /> ↓ ?br /> Parcel Remittance
↓ ?br /> PostParcel PostRemit
?wn) ?br /> MailPost
?.2 包ch4package的类和接口层?/p>
在C#目中添加引用Microsoft.VisualBasic.dll, 可以在C#E序中直接用VB.NET中丰富的函数