郝兴伟
山东大学计算机科学与技术学院
hxw@sdu.edu.cn
第六章 服务器端开发
目 录
6.1 Java技术及相关概念
6.2 Java程序设计基础
6.3 Servlet与三层体系结构
6.4 JavaBeans组件
6.5 JSP技术
6.6 ASP,JSP,PHP技术比较
6.7 Java开发工具简介
引言
-- Web应用:客户端 +服务器端
-- 服务器编程与 Web服务器
针对不同的 Web服务器环境,所用的开发工具也不相同,这
与 Web服务器中所包含的内置组件有关。
-- IIS,ASP技术
-- Tomcat,JSP技术
6.1 Java技术及相关概念
Java是 Sun公司开发的新一代编程语言。 Java是平台无关的,
使用它可在各式各样不同的硬件平台、不同操作系统平台的
网络环境中进行软件开发。具有“一次编写,到处运行”的
能力。
Java作为最强大的网络语言,随着新技术的不断兴起,新的
概念也层出不穷,如,Java Applet,Java Servlet,JavaBeans、
EJB,JDBC等。本节主要介绍与网络开发有关的概念以及它
们之间的关系。
6.1.1 Java概述
1,Java的出现
1991年,Sun计划开拓消费类电子产品市场,为电视、烤面包
箱等家用消费类电子产品开发一个分布式代码系统,目的是
可以通过 Internet与家电产品进行交互,以便对其进行控制。
Sun内部人员把这个项目称为 Green,该小组的领导人是 James
Gosling
1991年 6月 Gosling开始准备基于 C++开发一个新的语言,看着
窗外的一棵老橡树,就将这个新的语言命名 Oak,他就是 Java
的前身。
Java的设计思想
一、软硬件环境
Gosling在开始写 Java时,并不局限于扩充语言机制本身,更
注重于语言所运行的软硬件环境。他要建立一个系统,这个
系统运行于一个巨大的、分布的、异构的网格环境中,完成
各种电子设备之间的通信与协同工作。
二、平台无关
Gosling在设计中采用了虚机器码( Virtual Machine Code) 方
式,即 Java语言编译后产生的是虚拟机,虚拟机运行在一个
解释器上,每一个操作系统均有一个解释器。这样一来,
Java就成了平台无关语言。
6.1.2 Java的技术特征
在 Sun的 Java语言白皮书中,说明 Java语言有如下特征,
简单、面向对象、分布式、解释执行、健壮、安全、体系结
构中立、可移植、高性能、多线程、动态性 … 。
1,简单( Simple)
主要体现在三个方面
( 1) Java语言风格来源于 C++,因此 C++程序员可以很快的
上手。
( 2) Java拚弃了 C++中容易引发错误的地方,如:指针,增
加了内存管理等一些新的特色。
( 3) Java提供了丰富的类库,使用户编程更加简单。
2,面向对象( Object-Oriented)
Java是面向对象的语言,拚弃了 C++中全局变量等与面向对象
思想冲突的内容。
3,体系结构中立( Architecture Neutral)
一般情况下,网络环境都是异构的,如何使一个应用程序能
够在不同硬件、不同操作系统平台的计算机上运行,始终是
一个难题。
Java将他的程序编译成一种结构中立的中间文件格式,由 Java
虚拟机来解释执行这种中间代码。这使得 Java应用程序可以
在不同的处理器中执行,现在几乎所有的主流计算机系统都
能运行 Java。
4,解释执行( Interpreted)
Java解释器能直接的在任何机器上执行 Java字节码 (.class)
( Bytecodes)。
C:>java <.class文件 >
5,可移植( Portable)
同体系结构无关的特性使 Java程序可以在配备了 Java虚拟机
(Java Virtual Machine,JVM)的任何计算机系统上运行。
另外,通过定义独立于平台的基本类型及其运算,Java数据
得以在任何硬件平台上保持一致。
6,分布式( Distributed)
Java程序的程序库可以很容易的与 HTTP和 FTP等 TCP/IP协议
配合,从而使 Java程序可以凭借 URL打开并访问网络对象,
对程序员来讲,访问方式和访问本地文件系统几乎一样,这
就为 Internet等分布环境提供内容带来了方便。
7,安全性( Secure)
Java是被设计用于网络和分布式环境的,安全性自然是一个
重要的考虑因素。 Java的安全性可以从两个方面考虑,
( 1)内存的安全性,如拚弃了 C++中的指针,从而避免了非
法内存操作和内存泄漏。
( 2)当用 Java来创建浏览器内容时,语言功能和浏览器本身
的功能结合,使他更安全。
6.1.3 Java语言的特点
1,Java没有主函数和全局函数
2,Java没有全局变量
3,Java没有结构和联合
4,字符串不再是字符数组
5,Java用 Package来分解命名空间
6,Java没有独立的头文件
7,数据类型
8,常量修饰符 const的使用限制
1,Java没有主函数和全局函数
( 1) C++并非完全意义上的面向对象语言,例如:在 C++中,
必须有一个独立的主函数(在 Dos和 Unix下是 main(),在
Windows下是 WinMain()),还可以定义直接使用的全局函数等
( 2) Java是完全面向对象的语言,他没有主函数等完全孤立的
东西,任何函数都必须隶属于一个类。
当然,任何程序都有一个入口,Java程序也有主入口函数,名
称同样是 main(),但它必须包含在一个类中,一般形式是,
Public class AppName{
Public static void main(String args[]) {
… // 代码
}}
2,Java没有全局变量
在 Java程序中,不能在所有类外面定义全局变量,只能通过在
一个类中定义 公用静态变量 来实现全局变量。例如,
class GlobalVar {
public static GlobalVarName; // 全局变量定义
}
因为 public static成员是一种类属成员变量,只要定义了类,其
中的类属成员变量就分配空间,而不需要必须声明类的对象。
使得其他类可以访问和操作该变量。
可见,在 Java中,对全局变量进行了更好的封装。而在 C++中,
不依赖于任何类的不加封装的全局变量往往会导致系统崩溃。
3,Java没有结构和联合
在 C++中,为了保持和 C的兼容,继续支持结构( struct) 和联
合( union)。 但是,在 Java中,则完全拚弃了这些面向过程时
代的概念。
4,字符串不再是字符数组
在 C和 C++中,字符串操作往往会导致许多内存问题,如内存非
法操作、内存泄漏等。
因为字符串 char *s和不定界的字符数组 char s[]是等价的。但两
者只是为变量 s分配一个指向字符串的指针,存储字符串内容的
内存需要申请和释放。
在 Java中,字符串和字符数组已经被分开了。字符串是一个完
全意义上的对象,需要用 String类来定义。
5,Java用 Package来分解命名空间
问题:在大型的软件工程中,如何避免程序员和程序员之间、
程序员和系统供应商提供的类不重名呢?
在 Java中,引入 Package概念来解决上述问题。 Package有效的
通过集合类来划分命名空间,在不同包内的类可以同名,但不
会引起混乱。
Java并没有彻底解决命名冲突的问题,扩展基类可能引起派生
类的冲突。例如:用户派生一个类,增加一个方法 foo。 如果以
后供应商提供新的版本,在新类中也包含了 foo方法,冲突就出
现了。
6,Java没有独立的头文件
在 C++中,每一个,cpp实现文件都对应一个,h头文件,在头文件
中,往往包含了,cpp文件中用到的类的定义。
在 Java中,关于类的一切东西(属性和方法)都被放到一个单
独的文件中,类中方法的实现必须在定义的过程中同时进行。
因为类方法的实现代码必须在方法定义时完成,但是一个函数
的代码往往是几十行或者几百行的程序代码,这样就使得阅读
类很难一下子就看到一个类的全貌。
Java的设计者已经考虑到了这问题,为此,在 JDK中提供了两个
工具来补偿,Javap来打印类标识,Javadoc为源代码提供标准
的 HTML文档。
(开发环境 JBuilder,NetBeans IDE 等会提供不同的视图)
7,数据类型
( 1)在 C/C++中,对于不同的平台,编译器对简单数据类型 int、
float等分配不同长度的内存空间。
但是在 Java中,对于这些基本数据类型,总是分配固定长度的
空间,int总是 32bit,这就可以保证 Java的平台无关性。
( 2)在 C/C++中通过指针可以进行强制类型转换,这往往会带
来不安全性。在 Java中,有严格的类型相容性检查。
( 3)在 Java中,没有模板类,而 C++中的模板类(参数化类,
即形式参数对应的实际参数是数据类型)可以有效的简化程序
代码的编写,但不能减少可执行代码的长度。这就意味着,在
Java中,只能靠相似代码的手工复制和修改
8,常量修饰符 const的使用限制
在 C++中,const常量修饰符有着重要的应用,它对于提高代码
质量起到了积极的作用。例如,用户可以声明函数参数或者函
数的返回值为 const类型,这样可以有效的防治在函数内部对函
数参数的不正当修改或者对返回值的修改。另外,可以将类的
一个成员函数声明为 const,表明该方法不能修改他操作的任何
对象。
在 Java中,支持常量操作符、只读变量,通过 final关键字实现。
但是,Java没有提供一种机制,使得一个变量在参数传递或者
返回的过程中只读,或者定义一个不能修改操作对象的常量方
法。上述的省略,为 Java程序带来了一个可能引起不正当修改
错误的隐患。
6.2 Java程序设计基础
Java程序设计和 C/C++等一般的程序设计语言类似,都包含基本
符号、数据、数据类型、表达式、流程控制、类与对象等程序
设计的概念。
另外,Java程序设计语言还包含了一些自身的特点。例如:接
口、包、小程序等。
6.2.1 基本符号
1,基本字符
字母、数字、特殊符号
2,保留字(关键字)
由字母构成的具有固定含义的单词,如 if 代表条件语句
3,标识符
在 Java程序中,表示数据类型、类、接口、变量、方法(函数)
等名称的符号。
4,注释
( 1)以, //” 开头的单行注释;
( 2)以, /* … … */” 标记的块注释;
( 3)以, /** … … */” 标记的文档注释
6.2.2数据、数据类型和表达式
程序是对数据的处理,数据分成常量和变量,无论是常量还是
变量,每个数据都由一个相应的数据类型。
1,常量和变量
( 1)常量 是指在程序执行过程中,其值不发生变化的量。根据
类型不同,常量可分为整型常量(如 123,-15)、实型(浮点
型)常量(如 12.34)、字符常量(如 ‘ x’),布尔常量(如
true) 等。
( 2)所谓 变量,是指在程序执行过程中,其值发生变化的量。
每一个变量都有一个变量名,变量名是一个用户自定义标识符,
每个变量都有一个数据类型。类型决定变量在内存中所占空间
的大小,同时决定变量的取值范围和操作运算。
和 C/C++不同,Java中没有全局变量,所有的变量都被封装在类
中,成为类的成员变量。
2.数据类型
Java的数据类型可分为基本数据类型和构造数据类型。
( 1)基本数据类型
基本数据类型包括整型( byte,short,int,long),浮点型
( float),双精度型( double),布尔型( boolean) 和字符
型( char)。
( 2) 构造类型
在 Java中,没有 C/C++中面向过程的结构和联合。 Java中的构造
类型是用类来描述的,如数组、字符串、对象、类等。
类型用于说明类中的成员变量或成员函数的返回值。一般形式
是,
<类型名 > <变量 1,变量 2,…… 变量 n>;
3.表达式
表达式是由常量、变量、函数、运算符以及括号连接而成的式
子。
表达式的 分 类和类型转换
( 1)根据表达式运算结果的不同,表达式又分为算术表达式、
字符表达式、逻辑表达式等。
( 2)在 Java表达式中规定,整型、实型、字符型数据可以混合
运算。运算过程中,不同类型的数据会自动转换为同一类型,
然后再运算。
( 3)自动类型转换
按低级类型转换成高级类型数据的规则,转换规则为,
-( byte或 short) op int → int
-( byte或 short或 int) op long → long
-( byte或 short或 int或 long) op float → float
-( byte或 short或 int或 long或 float) op double → double
- char op int → int
( 4)把高级类型转换成低级类型,要通过强制类型置换。一般
形式是,(类型名)表达式
6.2.3 流程控制
每一种程序设计语言的语句都可以分为顺序、分支和重复语句
三种,只是使用的保留字和语法不同而已。
1.赋值语句和输入 /输出
2,分支语句
3,循环控制语句
1.赋值语句
无论是哪一种语言( C,Pascal,Fortran等),赋值语句、输
入和输出语句都是最基本的顺序语句。
( 1)赋值语句
在 Java中,赋值语句由赋值表达式加一个分号构成,一般形
式为,
<变量名 > = <表达式 >;
赋值语句的逻辑功能是将右边表达式的值赋给左边的变量。
2,分支语句
( 1) if 语句
一般形式是,
if (<表达式 >)
<语句 >;
( 2) if- else 语句
一般形式是,
if (<表达式 >)
<语句 1>;
else
<语句 2>;
( 3) switch语句
switch ( <表达式 >) {
case 常量 1,
语句 1
[ break; ]
case 常量 2,
语句 2
[ break; ]
… …
case 常量 n,
语句 n
[ break; ]
[default,
省缺处理语句
]
}
3,循环控制语句
( 1) while 语句
一般形式,
while (<表达式 >)
语句;
逻辑功能,
( 2) do -while语句
一般形式为,
do {
语句(循环体)
} while( <表达式 >);
循环控制语句(续)
( 3) for 语句
一般形式为,
for (表达式 1;表达式 2;表达式 3)
语句;
执行过程如下,
( 1)计算表达式 1。
( 2)计算表达式 2,如果为真,则执行循环体,转步骤( 3)。
否则,结束循环。
( 3)计算表达式 3
( 4)无条件转步骤( 2)
( 5)循环结束,执行 for语句下面的语句。
4.break语句和 continue语句
( 1) break语句用于跳出最近的循环(语句块 {…} ),一般
形式为,break;
例如,
for (i=0,p=1;true;i++) {
p *= 2;
if (p>1024) break;
}
( 2) continue语句用于结束本次循环,即跳过本次循环中下
面尚未执行的语句,接着进入下一次是否执行循环的判断,
一般形式为,
continue;
6.2.4 类与对象的概念
( 1)结构化程序设计
在 20世纪 90年代以前,自顶向下逐步求精的结构化程序设计
是软件开发的主要方法,直到现在,这种结构化的程序设计
思想仍然被广泛的采用。 Pascal,C,Basic,Fortran等高级
语言很好的实现了结构化编程的思想,通过过程和函数(又
称子程序),把一个复杂的问题划分成几个相对简单的子问
题,如果子问题还比较复杂,再继续划分,最后将划分后的
每个问题用过程和函数来实现。
( 2)面向对象技术
这一技术强调利用软件对象进行软件开发,它将自然界中的
物理对象和软件对象相对应,建立了类和对象的概念。由于
客观世界的实体和软件结构的对象一一对应,这样就增加了
系统的可扩展性和可维护性。
1,类与对象的概念
( 1)类( class) 是包含数据和处理这些数据的过程的数据
结构。我们可以将类看成是和 int,float等基本数据类型一
样的数据类型,用它来创建数据对象,它指定了相应内存区
域的处理和解释规则。
( 2)对象( object) 是用类来声明的数据结构,如果将类比
作数据类型,对象就是相应数据类型的变量。对象是类的实
例。
2,类的定义
在 Java中,类的定义一般形式是,
[修饰符 ] class <类名 > [extends 父类名 ] [implements
接口名列表 ]
{
成员变量声明;
成员函数定义;
}
( 1)修饰符
其中,修饰符决定类的类型,有四种,
· abstract,抽象类,抽象类必须包含至少一个抽象成员函
数。抽象类不能够创建对象,需要用其派生类创建。
· final,最终类,说明一个类不能再派生子类。
· public,能被其他类访问。在其它包里要使用该类,需要
先用 import导入,否则只能在他定义的 package里使用。
· Synchronicable,表示所有类的成员函数都是同步的。
上述修饰符可以同时出现两个或以上,但修饰符 abstract和
final不能同时使用。
( 2)扩展类和实现接口
class为关键字,类名是一个用户自定义的标识符。
如果是派生类,需要通过 extends给出父类。
如果定义接口( interface),需要给出 implents给出接口名。
( 3)成员变量
花括号内说明类的成员变量和成员函数,又称类的属性
( attribute) 和方法( mathod)。
( 1)成员变量定义的一般形式是,
[修饰符 ] <类型 > <成员变量列表 >;
其中修饰符为类成员的访问级别声明符号,可以是,private、
public,protected。 还可以添加的修饰符有,final( 最终,
初始化后不能再改变其值的变量),volatile( 多线程变量)。
这些访问级别可以按任何顺序出现,也可以多次出现。
如果成员变量包含修饰符 static,此变量称为 类变量,不加
static的变量称为 对象变量 。
( 4)成员函数
成员函数又称类的方法( method),是类中定义的可对类进行
操作的函数模块。成员函数定义的一般形式为,
[修饰符 ] 返回值类型 <方法名 >( [形式参数列表 ] ) [throws
异常列表 ]
{
// 函数体( Java程序代码)
}
修饰符可以是,private,public,protected和 final( 最终,
不能由子类改变的方法),abstract( 抽象方法,无方法体)、
synchronized( 线程同步的方法),native( 本机方法)。另
外,还可以有 static来声明静态成员函数,表明此方法为类方
法,无 static修饰的方法为对象方法。
3,构造函数
构造函数( constructor) 是一种特殊的成员函数,用来在内存
中建立具体的对象。构造函数必须申请必要的内存空间,将内
存转化为具体的对象,初始化成员变量等。
构造函数的名称和类名称相同,一个类可以拥有几个带有不同
参数的构造函数。
构造函数没有返回类型和返回值。
和一般的函数不同,构造函数不是由用户显式调用( call) 的,
它是通过编译器来调用的,称为激活( invoke)。
4,构造函数规则和特殊情况
( 1)构造函数不能描述为 const和 volatile。
( 2) 构造函数不能是 static,因为构造函数需要初始化类的成
员变量,但静态构造函数不能访问成员变量。
( 3)构造函数不能被继承。当一个没有构造函数的类从一个含
有构造函数的类派生时,将写它自己的构造函数。
( 4)构造函数不能有返回值,也不可以是 void。
( 5) 定义一个类时,必须明确定义除缺省构造函数和拷贝构造
函数以外的所有其它构造函数。
5,创建对象
当定义类后,可以使用 new来创建对象,一般形式是,
对象变量 =new 类(参数);
如果类的构造函数带有参数,可以通过 new中类名后面的参数,
来激活相应的构造函数。
[例 6-1] 类的定义举例
在下面的例子中,定义了一个类 A,包含几个属性和几个成员函
数,文档名为 exam6-1.java,内容如下,
class CTriangle
{
private double a,b,c,t;
public double s=0;
CTriangle(double x,double y,double z)
{
a=x; b=y; c=z;
}
//计算三角形的面积
public double Area()
{
t=(a+b+c)/2;
s= Math.sqrt(t*(t-a)*(t-b)*(t-c));
return s;
}
代码续
public void out1()
{
Area();
System.out.println("Area="+s);
}
}
//////////////////////////////////////////////////
//定义包含 main的类
class MyTest01
{
public static void main(String[] args)
{
CTriangle myobj = new CTriangle(10,20,15);
myobj.out1();
}
}
编译及运行
在 Dos提示符下,执行
javac exa01.java命令,编译,生成每个类的,class文件;
然后执行
java MyTest01。 运行上述程序,
输出结果如下,
Area=72.61843774138907

[例 6-2] 类的构造函数激活次序举例
在下面的例子中,定义了三个类 A,B,C,其中 C中包含两个
对象成员,来展示对象构造函数的激活次序,文档名为
exa02.java,内容如下,
class A {
int x,y;
A(int a,int b)
{
x=a; y=b;
}
A()
{
x=0; y=0;
System.out.println("A constructor\n");
}
}
代码续 1
class B {
B()
{
System.out.println("B constructor\n");
}
}
class C {
public A a=new A();
public B b=new B();
C()
{
System.out.println("C constructor\n");
}
}
代码续 2
class MyTest02
{
public static void main(String[] args)
{
C myObj=new C();
}
}
编译及运行
4.2.5 封装和抽象
封装( encapsulation) 是指对象可以拥有私有元素,将内部细
节隐藏起来的能力。封装将对象封闭起来,管理着对象的内
部状态。
抽象( Abstract) 则和对象的外部状态紧密相关,它通常用来
描述对象所表示的具体概念、对象所完成的任务以及处理对
象的外部接口。抽象处理的是对象的可见外部特征。
在 C++和 Java等面向对象的程序设计语言中,类的每一个成员
都被说明成 public,private和 protected型,用这些关键词来实
现数据的抽象和封装。
关键词 public,private和 protected
1.关键词 public
类中所有 public成员构成类的接口,它们是类的抽象性的表现。
2.关键词 private
类中的 private成员只能被类的成员函数、友元类或外部友元函
数访问。从而实现类的封装性。
在默认状态下,所有的成员都是私有的。
3.关键词 protected
在面向对象技术中,派生是类的重要性质。类的 private成员将
不能被派生类中的成员访问,这就大大限制了类的灵活性。
类的 protected成员可以被类的派生类成员访问。
类成员访问规则
4.2.6 静态成员
当一个成员被说明成 static时,则该成员在程序中只有一个拷贝
存在,而不是在每个对象中都有一个拷贝。所有的对象共享类
中的静态成员。在一些面向对象的程序设计语言中,静态成员
被称为类变量。或类属变量。
例如,定义一个含有静态成员变量的类如下,
class CS {
static int a;
int b,c,d;
};
CS objs[3];
4.2.7 类的继承性与派生类
从现存的对象出发建立一种新的对象类型,使它继承原对象的
特点和功能,这就是对象的继承性。继承是许多层次对象的自
然描述。
现存类派生出新类时,现存类称为基类( base class),派生出
的新类称为派生类。派生类可以对基类作如下变化,
· 增加新的成员变量
· 增加新的成员函数
· 重新定义已有的成员函数,即:子类可以对父类的方法覆盖
( overriding) 或重载( overloading)。
类的继承性与派生类 (续)
( 1)所谓覆盖( overriding),是指在子类中定义了与父类中
同名的函数,这时将根据当前的对象类型执行子类中的代码,
即父类中的代码被覆盖。
--运行时多态( C++的虚函数)
( 2)所谓方法重载( overloading) 是子类与父类的方法同名,
但是形式参数不同时,将重新实现该方法。
-- 编译时多态
类的继承性与派生类 (续 2)
类的派生是一种演化过程,即通过扩展( extends),更改和特
殊化从一个已知类出发来建立一个新的类。类的派生建立了一
个具有共同关键特性的类族,从而实现代码的重用。假设从一
个已知基类 A建立一个派生类 B,一般形式为,
class B extends A {
// 派生类 B的成员说明
};
读作, 类 B由 A派生,,它告诉
编译器类 B是一种 A,对基类 A所
作的修改和添加在括号内给出。
[例 6-3] 对象成员的访问举例
下述例子演示了类及其派生类中,成员的访问规则,文档名
exa03.java,代码如下,
class B {
private int x,y;
protected int z;
B() // 构造函数 1
{
x=0; y=0; z=0;
System.out.println("A constructor\n");
}
B(int a,int b) // 构造函数 2
{
x=a; y=b;
z=x+y;
}
}
代码续 1
class D extends B{
D(int x,int y) // 构造函数
{
System.out.println("D constructor\n");
}
public void out()
{
System.out.println("D public out Access class
B:z="+z); // 访问父类的 protected成员
}
}
代码续 2
class MyTest03
{
public static void main(String[] args)
{
D myd= new D(10,20); // 创建派生类对象
myd.out(); // 外部访问
}
}
编译及运行
执行 java MyTest03,运行结果为,
A constructor
D constructor
D public out Access class B:z=0
从上面的例子可以看出, 创建一个派生类的对象, 首先执行父
类的构造函数 1,然后再执行本身的构造函数 。 在派生类中,
可以访问父类的 protected成员 。
类 A
类 D
4.2.8多态性和抽象类
多态性( polymorphism) 是指相同的操作作用于不同类的对象
时,可以得到不同的结果。多态主要表现为编译时多态和运行
时多态两种形式。
所谓编译时多态主要包括操作符重载和函数(方法)重载。在
程序编译时,系统根据传递的参数的个数和参数类型等信息决
定要连接的函数。
运行时多态是指直到系统运行时才根据操作对象的类来决定执
行何种操作,即执行哪个类中的方法。
重写与重载
方法的重写 (Overriding)和重载 (Overloading)是 Java多态性的不
同表现。
(1)重写 (Overriding)是父类与子类之间多态性的一种表现,
(2)重载 (Overloading)是一个类中多态性的一种表现。
如果在子类中定义某方法与其父类具有相同的名称和参数,我
们说该方法被重写 (Overriding)。 子类对象使用这个方法时,将
调用子类中的定义,对它而言,父类中的定义如同被, 屏蔽,
了。
如果在一个类中定义了多个同名的方法,它们或有不同的参数
个数或有不同的参数类型,则称为方法的重载 (Overloading)。
[例 6-4] 编译时多态性举例
定义一个类,包含两个成员函数 Area,分别用于计算矩形和圆
的面积,文档名为 exa04.java代码如下,
class CFigure
{
public double s=0;
public double Area(double a,double b)
{
s=a*b;
return s; //计算矩形的面积
}
public double Area(double r)
{
s=3.14*r*r;
return s; //计算圆的面积
}
}
代码续 1
class MyTest04
{
public static void main(String[] args)
{
CFigure myobj = new CFigure();
System.out.println("Rectangle
area="+myobj.Area(10,20));
System.out.println("Circle
area="+myobj.Area(10));
}
}
编译及运行
[例 6-5] 运行时多态性举例
下面是一个演示 Java中类的多态性的例子,文档名为
CMyFigure.java,内容如下,
public abstract class CMyFigure // 定义抽象类
{
//public abstract void Draw();
public abstract void Area(); // 声明一个抽象函数
}
代码续 1
class CRectangle extends CMyFigure // 派生类
{
float height,width;
float s;
CRectangle(int x,int y)
{
height=x;
width =y;
}
public void Area() // Overriding父类中的抽象函数
{
s=height*width;
System.out.println("The Area of the Rectangle="+s);
}
}
代码续 2
class CCircle extends CMyFigure // 派生类
{
float r,s;
CCircle(float x)
{
r=x;
}
public void Area() // Overriding父类中的抽象函数
{
s=(float)3.14*r*r;
System.out.println("The Area of the Circle="+s);
}
}
代码续 3
class MyTest05
{
public static void main(String[] args)
{
CMyFigure objs[]; // = new CMyFigure[2]; 创建数组
objs[0] = new CRectangle(10,20);
objs[1] = new CCircle(10);
for (int i=0;i<2;i++)
objs[i].Area();
}
}
在上述代码中,将 obj1和 obj2均声明为 CMyFigure类,但在程
序运行时实际存储的是派生类 CRectangle和 CCircle对象。执
行 obj1.Area()和 obj2.Area()的代码是在程序运行是执行了 new
对象后确定的,这是一种运行时多态。
4.2.9 接口
( 1)当一个类需要从多个基类派生时,派生类将继承多个基
类的特征,在 C++中,这样的机制称为多重继承。
( 2) Java没有多重继承,可以通过接口来实现多种功能。在
Java中,所谓接口( Interface) 是一组没有给出实现细节的
操作(方法)的集合。他需要别的类来实现接口给出的每一
个方法,一个类可以实现一个或多个接口。如果一个类实现
了某个接口,就相当于声明我能够完成某项工作。
1,创建接口
接口定义的一般形式是,
public interface <Interfacename> [extends
Superinterfaces]
{
成员变量声明(常量);
成员函数(方法)声明;
}
在接口定义中,public指示了接口可以在任何的包中任何的
类中使用。如果你没有指定接口为 public,那么接口就只能
在定义接口的包中类使用。
一个接口可以扩展另外的接口,这跟类可以扩展一样。但是,
类只能扩展一个另外的类,而接口可以扩展任意个接口。
Superinterfaces列出所有的被扩展的接口,以逗号分隔。
2,接口和类
接口的定义和类的定义类似,但是接口不是一个类,而是对
符合接口要求的类的一套规范。接口说明了实现接口的类该
做什么而不指定如何去做,一个类可以实现一个或多个接口。
实现一个接口需要 2个步骤,
( 1)声明类需要实现的接口,声明一个类实现一个接口需要
使用 implements关键字。
( 2)提供接口中的所有方法的定义。为了使用接口,需要编
写执行接口的类。一个类实现了某个接口,即这个类实现了
在接口中声明的所有方法,就相当于声明我能够完成某项工
作。
实现接口的类继承了定义在接口中的常量,这些类可以使用
简单的名字来引用接口定一中的常量。
[例 6-6] 一个抽象类和接口应用实例
( 1)定义抽象类 Animal
abstract class Animal { }
( 2)定义接口 LandAnimal
interface LandAnimal { }
( 3)定义接口 WaterAnimal
interface WaterAnimal { }
( 4)定义派生类 Dog,实现接口
class Dog extends Animal implements LandAnimal
{
}
( 5)定义派生类 Cat,实现接口
class Cat extends Animal implements LandAnimal
( 6)定义派生类 Duck,实现接口
class Duck extends Animal implements LandAnimal,
WaterAnimal
6.2.10 包 (package)
在 Java中,为了管理大型名字空间,避免名字冲突,引入包
( package) 的概念,包是由一组类和接口构成。
一般情况下,每一个类或接口都被存储在不同的文件中,为
了管理和使用方便,对于那些相关的类和接口可以绑定到一
个包中。
例如,Java的基本类在 java.lang中,而用于输入和输出的类
则在 java.io中。
1,定义包
使用 package语句可以将一个编译单元定义成包。如果使用
package语句,编译单元的第一行必须无空格,也无注释,格
式如下,
package 包名;
若编译单元无 package语句,则该单元被置于一个缺省的无名
的包中。
按照一般的习惯,包名是由,,” 号分隔的单词构成,第一个
单词通常是开发这个包的组织的名称。
举例
例如:有一个 java文件,文件名为 B.java,内容如下,
package Hao.gsl.lib;
public class B {
public void add(int i,int j)
{
System.out.println(i+j);
}
}
执行 javac -d d:\ B.java命令,则在 d:\目录下,创建一
个 d:\Hao\gsl\lib文件夹,包含编译后的类文件 B.class。
现在这个包已经创建好了,要使用这个包中的类 B,需要导入,
或者把 d:\yy\hao\ll设置在环境变量 classpath里。

2,使用包中的类和接口
要使用定义在一个包中的类和接口,可以通过 import关键词,
主要有两种形式,
( 1)在每个引用的类和接口前面给出它们所在的包的名字,
一般形式是,
acme.project.FooBar obj = new acme.project.FooBar();
( 2) 使用 import语句,导入类或接口,或包含它们的包。导
入的类和接口的名字在当前的名字空间可用。导入一个包时,
则该包中的所有的公有类和接口均可用,形式如下,
import java.util.*;
mydate=new Date();
其中,第一个语句表示 java.util中所有的 public类被导入当
前包,,*” 表示导入包中的所有类。在使用一个外部类或接
口时,要声明该类或接口所在的包,否则会产生编译错误。
2,使用包中的类和接口
要使用定义在一个包中的类和接口,可以通过 import关键词,
( 1)在每个引用的类和接口前面给出它们所在的包的名字,
一般形式是,
acme.project.FooBar obj = new acme.project.FooBar();
( 2) 使用 import语句,导入类或接口,或包含它们的包。导
入的类和接口的名字在当前的名字空间可用。导入一个包时,
则该包中的所有的公有类和接口均可用,形式如下,
import java.util.*;
mydate=new Date();
其中,第一个语句表示 java.util中所有的 public类被导入当
前包,,*” 表示导入包中的所有类。在使用一个外部类或接
口时,要声明该类或接口所在的包,否则会产生编译错误。
3,Java标准包
JDK为我们提供了很多标准的 Java类和接口,这些包是写 Java
程序所必需的,知道了每种包所包含的类和接口,并且熟悉
这些类和接口是每个 Java编程人员都应该掌握的基本技能。
( 1) java.applet,包含了一些设计小应用程序( Applet)
的类和接口
( 2) java.awt,是一个窗口工具箱包( Abstract Window
Toolkit,awt),包含一些 GUI界面相关的类,例如,Button、
Checkbox
( 3) java.io,包含文件输入 /输出类,FileInputStream和
FileOutputStream。
( 4) java.lang,包含 Java语言类、线程、异常、系统、整
数等相关的类,是 Java程序中默认加载的一个包。
( 5) java.net,该包支持 TCP/IP协议,并包含 Socket类、
URL,与 URL相关的类。
( 6) java.util,这个类包含一些程序的公用类,如 Date、
Dictionary类等。
6.2.11 Java Applet
Java Applet是指用 Java编写的能够在 Web页中运行的应用程
序,它的可执行代码称为 class文件。它具有安全,功能强和
跨平台等特性。
IE,Netcape和 HOT Java等主流浏览器都能够显示包含 Applet
的页面。
1,在 html中使用 Java Applet
首先编写 Applet源程序,扩展名为,java。 编辑完成后使用
javac命令将它编译转换成 字节码文件(,class文件),然后
再在 html文档中通过加入 <applet>标记 的方式将 Java小程序
引入到 html文档中。
一般形式是,
<applet width=,” height=,” code=“myJava.class”
codebase=“保存,class的路径 ">
浏览器不支持 Java的提示信息
</applet>
使用 Dreamweaver和 Frontpage插入 Java Applet
(1)在 Dreamweaver中,执行, 插入,,, 媒体,,”Applet”命

(2)在 Frontpage中,插入
2,Applet类
在包的介绍中,曾谈到过 Applet包,其中包含了 Applet类。
Applet类是所有 Applet应用的基类,所有的 Applet小应用程序
都必须继承该类。例如,
import java.applet.*;
public class myApplet extends Applet
{
… …
}
Applet类的基本方法 -1
Applet类的基本方法 -2
Applet类还有四个基本方法,以用来控制其运行状态,
( 1) init()方法,Applet程序运行前的初始化工作。当一个
Applet被系统调用时,系统首先调用该方法。
Applet类的基本方法 -3
( 2) start()方法:系统在调用完 init()方法之后,将自动调用
start()方法。而且,每当用户离开包含该 Applet的 Web页后再
次返回时,系统将再次执行 start()方法。
( 3) stop()方法:以用户离开 Applet程序所在的网页时,运
行该方法。因此它也是可以运行多次。
( 4) destroy()方法:停止 Applet程序的运行,撤消 Applet及
其所占用的资源。当在关闭浏览器时执行该方法。
<applet>标记所包含的属性
[例 6-7] 使用 JavaApplet举例
下面是一个创建 JavaApplet并在网页中使用的例子,依此来说
明 Java Applet的使用步骤。
代码
( 1 ) 编辑 Java Applet 源程序, 假定文档名为了
helloApplet.java,内容如下,
import java.awt.*;
import java.applet.*;
public class helloApplet extends Applet
{
public void paint(Graphics g)
{
g.drawString("Hello World!",5,35);
}
}将该文档保存在 d:\MyJava文件夹下 。
编译
( 2) 把 Applet的,java源程序转换为字节码,class文件
使用 javac helloApplet.java命令编译该文件, 生成,class文件 。
插入到 html
( 3) 编制使用 class 的 HTML文件 。 在 HTML文件内放入必要的
<applet>语句
在运行创建的 helloApplet.class 之前, 需要创建一个 html文件,
appletviewer或浏览器将通过该文件访问创建的 Applet。
创建的 HTML文档 myApplet.htm,保存在和,class相同的文件夹中,
内容如下,
<html>
<title>helloApplet</title>
<applet code="helloApplet.class“codebase = "D:/myJava,
width=200 height=100>
</applet>
</html>
显示 html
双击 htm文档, 在浏览器中将看到 Applet的执行结果 。
3,Applet交互
Applet支持鼠标、键盘等多种事件,从而可以使得用户可以对
Applet进行交互控制。
( 1) Applet的鼠标事件
Java Applet支持的鼠标操作有,mouseUp,mouseDrown、
mouseDrag,mouseEnter和 mouseExit等 。在 Applet类中包含了三种
事件的处理方法,用户只要在多个方法中加入适当的事件处理代
码,即可以完成相应事件的处理工作。三个方法的首部如下,其
中形参 x和 y是事件发生时鼠标指针的位置,
· public boolean mouseDown(Event event,int x,int y),按下鼠标按键;
· public boolean mouseUp(Event event,int x,int y),放开鼠标按键;
· public boolean mouseDrag(Event event,int x,int y),拖动鼠标;
· public boolean mouseEnter(Event e,int x,int y),鼠标指针指在对象
上;
· public boolean mouseExit(Event e,int x,int y),鼠标指针离开对象。
( 2) Java Applet响应的键盘事件
Java目前支持两种键盘事件,KEY_PRESS和 KEY_RELEASE。 当
按下键盘的某一键时发生 KEY_PRESS事件;当放开被按下的键
时发生 KEY_RELEASE事件。用 keyDown和 keyUp方法处理键盘
事件,两方法的首部如下,
· public boolean keyDown(Event event,int KeyPressed);
· public boolean keyUp(Event event,int KeyPressed)。
形参 event表示了事件本身对象,该对象的 id成员保存了事件发生
时对象的当前值,它与 Event对象的一组成员变量相对应。
形参 KeyPressed对应于所按键的值。对于常规键,其值为 ASCII码
【例 6-8】
设计一个 Java Applet程序,当在 Applet窗口内点击鼠标时显示鼠
标指针的( x,y) 坐标值。当按键时显示所按键的键值和对应的
字符。
代码 1
Java Applet代码如下,文档名为 MouseAndKeyApplet.java。
import java.awt.Event;
import java.awt.Graphics; overriding 父类 Applet的
import java.applet.*;
public class MouseAndKeyApplet extends Applet
{
String mouseDownInf=null; //保存按下鼠标时的显示信息
String mouseDragInf=null; //保存拖动鼠标时的显示信息
String mouseEnterInf=null; //鼠标指向或离开 Applet对象时的显示信息
String keyDownInf=null; //保存键盘操作信息
public boolean keyDown(Event evt,int key)
{ //按下键盘键时发生的事件
keyDownInf="按键,"+(char)key+" 键值,"+key;
repaint(); //重画对象
return true; //返回 true表示事件处理成功
}
代码 2
public boolean mouseDown(Event evt,int x,int y)
{ //点击鼠标左键或右键时发生的事件
mouseDownInf="点击位置, ( "+x+","+y+") ";
repaint();
return true;
}
代码 3
public boolean mouseDrag(Event evt,int x,int y)
{ //按住鼠标按键拖动时发生的事件
mouseDragInf="拖动位置, ( "+x+","+y+") ";
repaint();
return true;
}
代码 4
public boolean mouseEnter(Event evt,int x,int y)
{ //鼠标指针指向 Applet对象时发生的事件
mouseEnterInf="Hi,Welcome! ";
repaint();
return true;
}
代码 5
public boolean mouseExit(Event evt,int x,int y)
{ // 鼠标指针离开 Applet对象时发生的事件
mouseEnterInf="Bye";
repaint();
return true;
}
代码 6
public void paint(Graphics g)
{ // 显示 Applet对象的方法
if (mouseDownInf!=null)
g.drawString(mouseDownInf,25,90);
if (mouseDragInf!=null)
g.drawString(mouseDragInf,150,90);
if (keyDownInf!=null)
g.drawString(keyDownInf,280,90);
if(mouseEnterInf!=null)
g.drawString(mouseEnterInf,200,45);
}
} / / 类 MouseAndKeyApplet 定义结束
myApplet2.htm
下面是调用 Java Applet的 htm文档,文档名为 myApplet2.htm,内
容如下,
<html>
<head>
</head>
<body>
<p><font color="#FF0000" size="5">JavaApplet中的鼠标和键盘
事件演示 </font></p>
<hr>
<applet code = "MouseAndKeyApplet.class" width=500
height=100>
</applet>
</body>
</html>
如果 html和 applet文件,class在同一
文件夹中,可以省略 codebase参数
6.2.12 Java的多线程机制
1,程序和进程
“进程( Process),定义为“可并发执行的程序在一个数据集
合上的运行过程”。可以通俗的讲,进程是内存中执行中的程
序,但是进程和程序是两个截然不同的概念。进程是操作系统
进行资源分配的单位,进程是动态的,程序是静态的。有人把
进程解释为程序的一次运行,这种解释是不确切的。实际上,
程序运行并不创建一个新的进程,并且程序一次运行可以创建
多个进程。
2,线程
线程( Thread) 是一种特殊的进程,他是进程下能够独立运行
的更小的单位,线程运行在进程空间内。多线程程序设计是指
在单个程序中包含并发执行的多个线程。当多线程程序执行时,
该程序对应的进程中同时有多个控制流并发运行,不同的线程
共享进程的资源。
1,Java中多线程的实现
第一种方法是从 Thread类派生一个线程类,覆盖它的 run()方法,
代码形式如下,
public class myThread extends Thread
{
public void run() {
// here is where you do something
}
}
第二种方法是通过实现 Runable接口,创建一个可执行类,实现
它的 run()方法,代码形式如下,
public class myRunable implements Runnable
{
public void run() {
// here is where you do something
}
}
2.线程的创建、启动和终止
启动一个线程只需要调用 start()方法,针对两种实现线程的方法
也有两种启动线程的方法,分别如下,
( 1)继承 Thread类方式
myThread aThread = new myThread (); //创建一个线程对象
aThread.start(); // 启动线程
( 2)实现 Runnable接口方式,是通过实现 Runable接口创建一个
可执行类,并利用一个 Thread对象来启动线程
myRunnable aRunable = new myRunnable (); // 创建一个可执
行对象
Thread aThread = new Thread(aRunable); // 创建一个线程
对象,并与可执行对象关联
aThread.start(); // 启动线程
【例 6-9】
编写一个 Java程序,创建二个线程,分别在屏幕上输出字母, a”
和, b”。
根据上面的介绍,我们采用派生 Thread类的方法,创建进程,
文档名 HelloThread.java,代码如下,
代码 1
import java.io.*;
import java.lang.*;
public class HelloThread 非派生类
{
public static class MyThreadClass1 extends Thread
{
long num1=0;
public void run()
{
while(num1<10000)
{
System.out.print("a");
num1++;
}
}
}
代码 2
public static class MyThreadClass2 extends Thread
{
long num2=0;
public void run(){
while(num2<10000)
{
System.out.print("b");
num2++;
}
}
}
代码 3
public static void main(String args[])
{
Thread MyThread1=new MyThreadClass1();
Thread MyThread2=new MyThreadClass2();
MyThread1.start();
MyThread2.start();
}
}
使用 javac HelloThread.java命令编译该文件为,class文件。然后
使用 java HelloThread运行该程序。运行时将看到在输出窗口中
不停地显示二个字母。

使用 javac HelloThread.java命令编译该文件为,class文件。然后
使用 java HelloThread运行该程序。运行时将看到在输出窗口中
不停地显示二个字母。
谢 谢 大 家