类的构造方法

Download Report

Transcript 类的构造方法

全国高职高专计算机技能型人才培养系列规划教材
Java程序设计基础
第5章 面向对象程序设计
www.avceit.cn
Contents
1
面向对象程序设计概述
2
类(class)
3
类的特性
4
接口(interface)
5
包
第5章 面 向 对 象 程 序 设 计
前面主要学习了Java语言的数据类型、控
制结构、数组等基本知识。作为Java学习
者,必须将自己的思维转入面向对象的轨道。
本章主要任务:





理解面向对象编程的基本概念
掌握类和对象的创建方法
了解成员变量和成员方法的特性
学习使用面向对象编程方式进行程序设计
理解接口和包的概念
5.1
面向对象程序设计概述
Java是一种面向对象的程序设计语言。
现实世界里的任何事物,都可以被看作对象。
对象是面向对象技术的一个基本概念。
类是组成java程序的基本元素。
下面逐一学习面向对象程序设计的有关概念。
5.2
类(class)
5.2.1 类的声明
类是一组具有相同或相似属性和行为对象的抽象
描述。
类封装了对象的属性和方法,它是用来定义对象
的类型,而对象就是类的一个实例。
创建类的一般格式:
[修饰符] class 类名 [extends父类名]
[implements接口名列表]{
 成员变量声明
 成员方法声明
}
其中,class、extends和implements都是
Java的关键字(保留字)。
类的修饰符主要有public、abstract 、final
及缺省访问修饰符等四种。
注意:一个类可以同时有多个修饰符,但
是不能有相同的修饰符。当一个类有多个
修饰符时,这些修饰符无先后顺序,可任
意排列。
在java中允许定义没有任何成员的空类。
【例5.1】 定义一个名为Box表示立方体的类,仅
包含double类型的长length、宽width和高height
三个成员变量。
 class Box{
 double length;
 double width;
 double height;
}
通过例5.1,我们可以看到,在类中进行成员变量
的声明与一般变量的声明形式完全相同,成员变
量的类型可以是任意的,成员变量的名字在一个
类中应该保证唯一性。例5.1中的类没有任何方法,
下面再看一个有成员方法的类。
【例5.2】定义一个名为Box表示立方体的类,包含double类
型的长length、宽width和高height三个成员变量以及设置
立方体长、宽、高值的方法initBox()、计算立方体体积的
方法getVol()。
class Box{ // 定义Box类
double length;
double width;
double height;
double getVol(){ // 计算立方体体积的方法getVol()
return length * width * height; }
void initBox(double l,double w,double h){
// 初始化立方体长宽高值
length = l;
width = w;
height = h; }
}
一旦定义了所需的类,就创建了一种新的
数据类型,使用类类型定义的变量叫对象
如:Box box1;
定义的box1是一个对类型为类Box的对象的
引用,box1不是对象本身,可理解为指针,
可以指向类Box的某一个具体的对象(实
例)。
5.2.2 类对象
创建类的变量称为类的实例化。
类的对象是在程序运行中创建生成的,其
所占的空间在程序运行中动态分配。当一
个类的对象完成了它的使命,为节省资源,
Java的垃圾回收程序就会自动收回这个对
象所占的空间,即类对象有自己的生命周
期。
1.创建对象
创建类的对象一般需要两步:
第一步,声明该类型的一个变量;
第二步,用new运算符为对象动态分配(即在运行
时分配) 内存空间,并返回对它的一个引用,这个
引用被存储在该变量中。
利用new创建类的对象的通用形式如下:
 类对象名 = new 类名();
例如,创建一个Box类的对象myBox可用以下语
句
 Box myBox;
 myBox = new Box();
new运算符允许与类声明结合使用来创建一
个类的对象,如上面两行语句可组合为:

Box myBox = new myBox();
定义好后,可以把myBox作为类Box的对象
来使用,而实际上myBox仅是保存了实例
对象的地址,利用它来间接的引用实例对
象。
2.引用对象
创建了类的对象后,就可以对对象的各个成员进
行访问,以进行各种处理。访问对象成员的通用
形式为
 类对象名 . 成员变量名
 类对象名 . 成员方法名( ) // 括号不能省略
运算符“. ”称为成员运算符,在类对象名和成员
变量名、成员方法之间起到连接的作用,以此指
明是哪个对象的成员。
从上面的访问形式,可以看出,要使用对象变量
首先要构造对象,获得类对象名,即类变量名。
【例5.3】利用例5.1定义的Box类,计算长、宽、高分别为5、
4、3的立方体体积。
public class BoxDemoOne{
public static void main(String args[]){
Box myBox = new Box();
double vol;
myBox.length = 5;
myBox.width = 4;
myBox.height = 3;
vol = myBox.length * myBox.width * myBox.height;
System.out.println("立方体的体积是: " + vol);
}
}
注意:要编译成功,必须将例5.1定义的Box类置于
本程序中,以生成Box.class和BoxDemoOne.class
两个字节码文件,程序运行结果如下:
 长方体的体积是: 60.0
当程序需要更多的类对象时,可用new运算符多次
创建该类的对象,然后按例5.3中的代码形式进行长
方体体积的运算。这样一来,程序中对成员变量的
访问赋值语句会很多,显得程序不够紧凑。更好的
方法是在类定义中加入可对成员数据进行操作的成
员方法(如例5.2所定义的类Box),可使程序更加
有效率。
【例5.4】用例5.2中定义的类Box来计算长、宽、高分别为5、
4、3和30、20、10的两个立方体的体积。
public class BoxDemoTwo{
public static void main(String args[]){
Box myBox1 = new Box();
Box myBox2 = new Box();
double vol;
myBox1.initBox(5,4,3);
myBox2.initBox(30,20,10);
vol = myBox1.getVol();
System.out.println("第一个立方体的体积是: " + vol);
vol = myBox2.getVol();
System.out.println("第二个立方体的体积是: " + vol);
}
}
 5.2.3 特殊的方法——构造方法
 例5.2定义的Box类,专门定义了一个方法initBox()用于对
成员变量length、width、height进行赋值初始化。如果在
一个对象最初被创建时就能够把它的相关值设置好,程序
将会更简单并且更明晰。Java语言允许对象在它们被创建
时初始化自己。这种自动的初始化是通过使用一种特殊的
方法——构造方法(constructor)来完成的。
 构造方法的任务就是初始化一个对象的内部状态,以便使
创建的实例变量能够完全初始化。它是一种特殊的成员方
法,它的特殊性反映在以下几个方面:
 构造方法名称与类名完全相同
 构造方法不返回任何值,也没有返回类型
 每一个类可以有零个或多个构造方法
 构造方法在创建对象时由Java编译器自动调用执行,一般
不能显式直接调用
构造方法的通用声明格式如下
[构造方法修饰符] 构造方法名([形式参数
列表])[throws异常列表]{
方法体
}
构造方法修饰符有:
public private protected
【例5.5】利用构造方法重写例5.4的实例。
class Box{ // 定义Box类
double length;
double width;
double height;
Box(double l,double w,double h){
// 利用构造方法初始化立方体长宽高值
System.out.println("Constructing Box");
length = l;
width = w;
height = h;
}
double getVol(){ // 计算立方体体积的方法getVol()
return length * width * height; }
}
public class BoxDemoThree{
public static void main(String args[]){
Box myBox1 = new Box(5,4,3);
// 在new执行前自动调用Box()方法
Box myBox2 = new Box(30,20,10);
double vol;
vol = myBox1.getVol();
System.out.println("第一个立方体的体积是: " + vol);
vol = myBox2.getVol();
System.out.println("第二个立方体的体积是: " + vol);
}
}
类的构造方法
 1、无参构造方法
 一个类若没有任何用户自定义的构造方法,Java会自动提
供一个空的无参数构造方法,在创建对象时,使用这个无
参的构造方法为类对象的成员变量赋数据类型的默认值。
 对于以下语句

Box myBox = new Box();
 利用new Box()调用构造方法Box()。
 如果我们不为类定义一个构造方法,Java将为该类创建一
个默认的构造方法(无参构造方法)。默认构造方法自动地
将所有的实例变量初始化为零。默认构造方法对简单的类
是足够的,但是对更复杂的类它就不能满足要求了。
 一旦我们在某个类中定义了自己的构造方法,默认的构造
方法将不再被使用。
2、有参构造方法
带有参数的构造方法能够实现这样的功能:当构造
一个新对象时,类构造方法可以按需要将一些指定
的参数传递给构造方法。
如例5.5所示:
Box(double l,double w,double h){
System.out.println("Constructing Box");
length = l;
width = w;
height = h;
}
【例5.6】带参数的构造方法应用实例。
class Point{
int x;
int y;
Point(int x,int y){ // 用户自定义带参数的构造方法Point()
this.x=x;
思考此处为什么要使用this?
this.y=y;
}
}
public class PointDemo{
public static void main(String args[]){
Point p=new Point(10,20);
System.out.print("类Point中的实例变量(x,y) = ") ;
System.out.println("( "+p.x+","+p.y+" )");
}
}
类的构造方法中的形式参数名与成员变量
名完全相同,这样在使用时会产生混淆。
在Java语言中,定义了关键字this来解决这
个问题。关键字this表示当前对象,可在引
用当前对象的所有方法内使用。
当然,这样使用this有时还是会引起混淆。
所以一些开发人员比较小心,一般不使用
和局部变量、正式的自变量同名的隐藏的
实例变量。
但关键字this仍然有其用武之地。如在某个
类中有多个构造方法时,一个构造方法可
以调用另外一个构造方法,调用的格式是
this(实际参数表);
该语句的功能是调用与this(指当前对象)中
参数匹配的构造方法。
在Java语言中,允许构造方法重载,即一
个类可以有多个构造方法。
【例5.7】构造方法的重载。
class OverloadBox{
double length;
double width;
double height;
OverloadBox(double l,double w,double h){
length = l;
width = w;
height = h;
}
OverloadBox(double x){
length = x;
width = x;
height = x;
}
double getVol(){
return length * width * height;
}
}
public class OverloadConstructorBoxDemo{
public static void main(String args[]){
OverloadBox myBox1 = new OverloadBox(30,20,10);
OverloadBox myBox2 = new OverloadBox(10);
double vol;
vol = myBox1.getVol();
System.out.println("第一个立方体的体积是: " + vol);
vol = myBox2.getVol();
System.out.println("第二个立方体的体积是: " + vol);
}
} 使用构造方法并非只是为了给对象赋初始值方便,更重要的是,它是确
保一个对象有正确起始状态的必要手段。另外,通过使用非public的构
造方法,可以防止程序被其他人错误地使用与扩展。
5.2.4
类和成员的修饰符
 前面的内容中,给出了定义类及其成员变量的通用
格式,在这些格式中,都使用了修饰符(modifier),
其目的是用来对类和成员的使用做某些限定。
 在Java中,一般将修饰符分为两类:
1. 访问控制符:public、protected、private、package
 作用是给予对象一定的访问权限,实现类和类中成
员的信息隐藏。
2. 非访问控制符:abstract、static、final、native、
synchronized、 volatile、 transient
 某些修饰符只能应用于类的成员,而某些修饰符既
可应用于类,也可应用于类的成员。
修饰符的作用范围
修饰符
类
子类
包
所有类和包
public
√
√
√
√
private
√
protected
√
√
√
package
√
√
public修饰符
public(公共)修饰符用来修饰类、类的成员
变量和成员方法。
用public修饰的对象能被所有的类访问;
public修饰的成员变量可以被项目文件中的
任何方法所访问。
由于public成员变量不受限制,这易使类的对
象引起不希望的修改,建议成员变量尽量
不要使用public修饰符。public修饰的方法
可以由其他类访问。
protected修饰符
protected(受保护)修饰符用来修饰类的成员变量
和成员方法。
protected修饰的成员变量和成员方法,可以被本
类和它的子类以及同一个包中的其他类访问。
private修饰符
private(私有)主要用来修饰类的成员变量和成员方
法。private修饰的成员变量和成员方法只能在本
类中被访问到,而不能被任何其它类(包括子类)所
引用。这种保护方式通常是最为安全的,也是对
类进行封装时使用的主要方法。
package修饰符
package(包)修饰的变量,称为包变量。
通常省略package关键字,即没有修饰符的
成员就是包成员。
包成员可以被本类及本类所在包中的其他
类访问。
 abstract修饰符
 abstract(抽象)用来修饰类、类的成员方法。
abstract修饰的类不能被实例化,它包含有未实
现的方法,需要子类继承。abstract修饰的方法
为抽象方法,无方法体。抽象类被派生、抽象方
法被子类实现后才有实际意义。
 注意:
1. 抽象方法只能出现在抽象类中。
2. 不能用abstract修饰构造方法、静态方法和私有
方法,也不能覆盖父类中的抽象方法,只有返回
值类型、方法名、方法参数,而不定义方法体的
方法
final修饰符
final(最终)修饰符用来修饰类、成员方法和
成员变量。final的含义为终极或最终,它修
饰的类不能被继承,即final类无子类。
final修饰的成员方法不能被覆盖,即子类的
方法名不能与父类中用final修饰的方法名相
同。
final修饰的成员变量称为最终成员变量。一开
始创建该变量时将其设定了一个值,在以后
程序的运行过程当中,变量的值将一直保持
这个值不变。如
 static final double PI = 3.14159;
 final int COUNTER = 10;
为final变量的所有字符选择大写是一个普遍的
编码约定。声明为final的变量在实例中不占用
内存。实质上,一个final修饰的变量就是一个
常量。
Java中的常量必须是类的成员。对于最终
成员变量,任何赋值都将导致编译错误。
因为常量在说明以后就不能改变其值,所
以常量必须要使用变量初始化来赋初值。
无论是实例变量,还是类变量,都可以被
声明成常量。
final修饰符和static修饰符并不冲突。但
abstract和final绝对不能同时作为一个类的
修饰符,因为abstract修饰的类必须要有子
类继承,而final修饰的类为终极类,不能有
子类继承。
【例5.8】常用修饰符的使用。
class Person{
private int a = 10; }
class Teacher extends Person{
public int b =50;
protected double c = 100.0; }
public class ModifierDemo{
public static void main(String args[]){
Person p = new Person();
Teacher t = new Teacher();
int i,j;
double k;
* i = p.a;
j = t.b;
k = t.c;
* System.out.println("In Person, value of a is: " + i);
System.out.println("In Teacher, value of b is: " + j);
System.out.println("In Teacher, value of c is: " + k);
}
}
上述程序中,加“*”的两条语句试图访问
私有成员a将会报错。如果我们注释掉这两
行,本例执行结果如下
 In Teacher, value of b is: 50
 In Teacher, value of c is: 100.0
成员b由于被public修饰,其值一定可以访
问;成员c由于被protected修饰,在其子
类及本包中可以访问到。
static修饰符
static(静态)修饰符用来修饰类的成员变量和成员
方法,以使它们成为静态成员(又称为类成员)。
静态成员存储于类的存储区,属于整个类,而不
属于一个具体的对象。因为静态成员属于整个类,
所以它被所有该类对象共享。在不同的类对象中
访问静态成员,访问的是同一个。
用static修饰的成员变量又称为类变量,不加
static修饰的成员变量又叫实例变量。实例变量依
附于具体的对象实例,它的值因具体对象实例的
不同而不同,而类变量为该类的所有对象所共享,
它的值不因类的对象不同而不同。
 用static修饰的方法为静态方法,又叫类方法;
无static修饰的方法为实例方法。类方法是该类
的所有对象共享的方法。
 对静态成员的使用一般应注意以下两点:
1. 静态方法不能访问属于某个对象的成员变量,而
只能处理属于整个类的成员变量,即静态方法只
能处理静态变量。
2. 可以使用两种方式调用静态成员,它们的作用相
同。
 变量:类名 . 变量名 或 类对象 . 变量名
 方法:类名 . 方法名() 或 类对象 . 方法名()
【例5.9】静态成员的使用。
class StaticDemo{
static int A=100;
static int B=200;
static void callMe(){
System.out.println("A = "+A);
}
}
class StaticByName{
public static void main(String args[]){
StaticDemo.callMe();
// 不需要创建对象,通过类名直接调用静态方法
System.out.println("B = "+StaticDemo.B);
// 通过类名直接调用静态变量
}
}
synchronized修饰符
synchronized(同步)修饰符用于修饰成员方
法或块。在多线程程序中,对用于共享的
方法和块加以互斥锁,使得任一时刻,
synchronized修饰的方法或块只能由一个线
程执行或操作。使用synchronized主要用以
设置同步机制,以实现线程的同步。
详见第10章
native修饰符
native(本地)修饰符一般用来声明用其它语言
如C、C++、FORTRAN、汇编等书写方法体并具
体实现方法功能的特殊方法。native修饰的方法
为本地方法,即方法实现与本机系统有关。native
方法可应用于实时性强、执行效率高、运行速度
要求较高的场合。
除了以上介绍的修饰符外,Java还为我们提供了
transient(过渡变量)、volatile(易失变量)等
修饰符,有兴趣的读者可利用Java API文档进一
步了解掌握。
 5.2.5 类的使用
1. 私有成员的访问
 在Java程序设计过程中,为了降低类间的
耦合性,提高代码的安全性,可以为类成
员指定private修饰符。用private修饰表示
该成员只能在该类内部被访问。若需要在
其它类中访问私有成员,只有通过取数和
送数等操作方法来访问。对于这样的方法,
我们常为其命名为getXxx()和setYxx()等
形式。
 【例5.10】私有成员的访问。
 class Box{

private double length;

private double width;

private double height;

Box(double l,double w,double h){

length = l;

width = w;

height = h;

}

double getLength(){

return length;

}
 double getWidth(){
return width;
}
 double getHeight(){
return height; }
}
 public class BoxDemoFour{

public static void main(String args[]){

Box myBox = new Box(6,5,4);

double vol;

vol = myBox.getLength() * myBox.getWidth() *
myBox.getHeight();

System.out.println("立方体的体积是: " + vol);

}
}
2.方法参数是类的对象
在Java语言中,方法的参数类型除了是基本类型
外,还可以是引用类型——类。在类的对象中实际
存储为对象的引用,因此在调用类参数时方法间传
送的是引用。尽管Java采用值传送,引用从调用
方法单向传送到被调方法,但由于调用方法与被调
用方法对应类参数的引用相同,它们引用同一对象。
所以,若在被调方法中修改了引用类型形式参数的
取值,则调用方法对应的实际参数也将发生相应的
变化。即调用方法与被调方法之间是“引用单向传
送,数据双向传送”。
应用引用类型的方法参数,可在方法间传递数据。
例5.11 引用类型的方法参数是方法间传送数据的桥梁。

















class Box{
double length;
double width;
double height;
double vol;
Box(Box box){
this.length = box.length;
this.width = box.width;
this.height = box.height;
}
Box(double l,double w,double h){
length = l;
width = w;
height = h; }
Box(){ // 用-1表示一个未初始化的Box对象
length = -1;
width = -1;
height = -1; }
Box(double edge){

length = width = height = edge;
}
double getVol(Box bx){

bx.vol = bx.length * bx.width * bx.height;
}
public class RefParameterBox{

public static void main(String args[]){

Box myBox1 = new Box(30,20,10);

Box myBox2 = new Box();

Box myCube = new Box(10);

Box myClone = new Box(myBox1);
}
 myBox1.getVol(myBox1);
 myBox2.getVol(myBox2);
 myCube.getVol(myCube);
 myClone.getVol(myClone);
 System.out.println("Volume of myBox1 is: "+myBox1.vol);
 System.out.println("Volume of myBox2 is: "+myBox2.vol);
 System.out.println("Volume of myCube is: "+myCube.vol);
 System.out.println("Volume of myClone is: "+myClone.vol);
 }
}
3.方法返回值为类的对象
 在Java语言中,方法的返回值类型也可以为引用类型,例
如一个方法返回值为类。
 【例5.12】方法的返回值类型为引用类型。
 class ReturnBox{
 double length;
 double width;
 double height;
 double vol;
 ReturnBox(double l,double w,double h){
 length = l;
 width = w;
 height = h;
 }
 ReturnBox getVol(ReturnBox box){
 box.vol =box.length * box.width * box.height;
 return box;
}
}
 public class ReturnObjectBox{

public static void main(String args[]){

ReturnBox myBox = new ReturnBox(20,15,10);

myBox = myBox.getVol(myBox);

System.out.println("立方体的体积是: "+myBox.vol);
 }
}
4.类对象作为类的成员
 类的数据成员也可以是引用类型的数据,如字符、字符串
和类等。若一个类的对象是一个类的成员时,要用new运算
符为这个对象分配存储空间。在包含类数据成员的类及类
的实例中可以访问类数据成员的成员。
 【例5.13】类对象作为类的成员。
 class BasedBox{

double length;

double width;

double height;

BasedBox(double l,double w,double h){

length = l;

width = w;

height = h;

}
}
 class ClassMemberInBox{ // 具有两个成员的类

BasedBox box = new BasedBox(5,4,3);

// 类成员要分配空间

double vol;
// 基本类成员
}
 public class ObjectToClassMemberBox{
 public static void main(String args[]){
 ClassMemberInBox myBox = new ClassMemberInBox();
 myBox.vol = myBox.box.length * myBox.box.width *
myBox.box.height;
 System.out.println("立方体的体积是: "+myBox.vol);

}
解释myBox.box.length的含义
}
5.嵌套类(Nested class)与内部类(Inner class)
当在程序的一个类中定义另一个类时,被
定义的类就称为嵌套类(Nested class)。
嵌套类的范围由装入它的类的范围限制。
例如,如果类ClassB被定义在类ClassA之
内,那么ClassB为ClassA所知,然而不被
ClassA的外面所知。
嵌套类可以访问嵌套它的类的成员,包括
private成员。但是,包围类(外层类)不
能访问嵌套类的成员。
嵌套类一般有两种类型:
前加static修饰符的嵌套类
不加static修饰符的嵌套类
注意:带有static的嵌套类不能直接引用它包
围类的成员,只能通过对象来访问。因为
有这个限制,所以static嵌套类很少使用。
嵌套类最重要的类型是内部类(Inner class)。
内部类是非static的嵌套类。它可以访问它
的外部类的所有变量和方法,它可以直接
引用它们,就象外部类中的其它非static成
员的功能一样。这样,一个内部类完全在
它的包围类的范围之内。
内部类是一个有用的特征,因为它允许将
逻辑上同属性的类组合到一起,并在另一
个类中控制一个类的可视性。
【例5.14】定义和使用一个内部类。在程
序中,名为Outer的类有一个名为outer_exp
的示例变量,一个名为testInnerMethod()的
实例方法,并且定义了一个名为Inner的内
部类。

class Outer{
int a = -100;
void testInnerMethod(){
Inner inner = new Inner();
inner.display();
}
class Inner{ // Inner被定义为内部类
void display(){
System.out.println("显示: outer_exp = " + a);
}
栈内存
}
}
Inner.display
public class InnerClassDemo{
this
public static void main(String args[]){
inner
Outer outer = new Outer();
outer.display
outer.testInnerMethod();
this
}
main
outer
}
堆内存
Inner类对象
Outer.this
Outer类对象
内部类仅在它的包围范围内是可知的
 例5.15 本程序用来说明内部类成员只有在内部类内可知,
且不能被外部类使用。程序代码是不能编译成功的。
 class Outer{

int outer_exp = -100;

void testInnerMethod(){

Inner inner = new Inner();

inner.display();

}

class Inner{ // Inner被定义为内部类

int Y = 100;

void display(){

System.out.println("显示: outer_exp = " + outer_exp);

}

}
void showY(){
System.out.println("Y = " + Y);

}
}
public class InnerClassDemoTwo{
public static void main(String args[]){
Outer outer = new Outer();
outer.testInnerMethod();

}
}
 例5.16 在程序块中定义内部类。

class Outer{

int outer_exp = -100;
 void testInnerMethod(){

for(int k=0;k<5;k++){

System.out.print("第 "+ (k+1) +" 次显示: ");

class Inner{ // Inner被定义为内部类

void display(){

System.out.println("outer_exp = " + outer_exp);

}

}

Inner inner = new Inner();

inner.display();

}

}
 }
 public class InnerClassDemoThree{

public static void main(String args[]){

Outer outer = new Outer();

outer.testInnerMethod();

}
}
 程序执行结果如下
 第 1 次显示: outer_exp = -100
 第 2 次显示: outer_exp = -100
 第 3 次显示: outer_exp = -100
 第 4 次显示: outer_exp = -100
 第 5 次显示: outer_exp = -100
嵌套类在日常的大多数编程中不会使用,
但当处理applet(Java小应用)时特别有帮助。
另外,嵌套类在Java最初的1.0版本中是不
允许的,直到Java1.1中才添加了嵌套类。
最后说明一点,由于内部类定义在一个类
中,因此内部类的名称不能与包围它的类
名相同,而且只能在定义的范围中使用。
下面是内部类具有的一些特性。
 内部类可以被定义在方法中。它可以访问嵌套类的方法的
final变量。
 内部类可以使用所嵌套类的类变量和实例变量以及所嵌套
的块中的本地变量。
 内部类可以被定义为abstract抽象类。
 内部类可被声明为private或protected,以便保护它们,使
得其不受来自外部类的访问。访问保护不阻止内部类使用
其他类的任何成员。
 一个内部类可以作为一个接口,另一个内部类实现。
 声明为static的内部类成为顶层类。这些内部类失去在本地
范围和其它内部类中使用数据或变量的能力。
 内部类不能声明任何static成员,只有顶层类可以声明static
成员。所以一个需求static成员的内部类必须使用来自顶层
类的成员。
5.3
类的特性
面向对象程序设计的三大基本原则是封装性、继承
性和多态性。
封装性是指在面向对象的程序设计中,对象的实现
过程(包括数据的存储方式、操作的执行过程)作为
私有部分被封装在类结构中,使用者不能看到,也
不能直接操作该类中所存储的数据,而只能根据对
象提供的外部接口来访问或操作这些数据。
对于封装性,我们在上一节关于类的定义内容中就
有所体现。下面重点介绍有关继承、多态的基本知
识。
5.3.1 继承性(inheritance)
继承性是面向对象编程技术的一大特性。
类继承也称为类派生,是指一个类可以继承其它类
的非私有成员,实现代码复用。
被继承的类称为父类或超类(superclass),父类(或
超类)包括所有直接或间接被继承的类;继承父类
或超类后产生的类称为子类(subclass)或派生类。
子类继承了父类的所有非私有的实例变量和方法,
并且可以有自己的成员。
类的继承反映了客观世界的层次关系,Java语言以
Object类作为所有类的父类,所有的类都是直接或
间接地继承Object类得到。Java还提供了不同层次
的标准类,使用户可根据需要派生自己的类。
在Java语言中,只允许单继承。但可通过
接口来实现多继承。
类继承不改变成员的访问权限,父类中的
成员为公有的或保护的,则其子类的成员
访问权限也继承为公有的或保护的。
(1)类继承格式
在Java中可通过关键字extends来实现继承。
声明格式如下
 class 子类名 extends 父类名{

…… // 子类体
 }
如有一个类A,声明一个类B继承自A的格式是

class B extends A{

……

}
这样子类B就拥有了父类A中的所有非私有
的成员,尽管A是B的父类,但其自身也是
一个完全独立的类。作为一个子类的父类
并不意味着父类不能被自己使用。而且,
一个子类可以是另一个类的父类,但没有
一个类可以是它自己的父类。
注意:若声明一个类时无extends子句时,
则该类为Object类的直接子类。
















【例5.17】子类与父类是继承关系的示例。
class SuperA{
int x = 10, y = 20;
void showXY(){
System.out.println("输出的 x 和 y 分别是: " + x +" " + y );
}
}
class SubB extends SuperA{ // 类SubB继承自类SuperA
int k = 30;
void showK(){
System.out.println("输出的 k 是: " + k );
}
void sum(){
System.out.println("输出的 x + y + k 是: " +( x+y+k ));
}
}
public class InheritanceDemoOne{
public static void main(String args[]){

SuperA superObj = new SuperA();

SubB subObj = new SubB();

superObj.showXY();

subObj.showK();

subObj.sum();

subObj.showXY(); // 子类继承了父类的
非私有方法showXY()

}
}
在上述程序中,类B中的方法
 void sum(){

System.out.println("输出的 x + y + k 是: "
+( x+y+k ));
 }
可以改写为
 void sum(){

System.out.println("输出的 x + y + k 是: "
+(super.x + super.y + k));

}
程序输出结果仍然保持不变。
 关键字super的作用是用来引用它直接的父类,
它有两种通用形式:
1. 调用父类的构造函数;
 super(参数列表);
注意:每个子类的构造方法都隐含了一条super();
语句,用来调用父类的构造方法,若父类中没有
无参构造方法,该程序将出错。
2. 访问被子类的成员隐藏的父类成员。
 super . 成员;
 这里的成员既可以是一个方法也可以是一个实例
变量。
 例5.18 关键字super应用实例。

class SuperA{

int x , y ;

SuperA(int x,int y){ // 父类中的构造方法

this.x = x;

this.y = y;

}

void showXY(){ // 父类中的方法showXY()

System.out.println("输出的 x 和 y 分别是: " + x +" " + y );

}
 }
 class SubB extends SuperA{ // 类SubB继承自类SuperA

int k;

SubB(int x,int y,int k){
 super(x,y); // 调用父类构造方法,是子类构造方法中第一个可执行语句

this.k = k;

}
 void showK(){

System.out.println("输出的 k 是: " + k );

}

void sum(){

System.out.println("输出的 x + y + k 是: "
+( super.x+super.y+k ));

}
 }
 public class InheritanceDemoTwo{

public static void main(String args[]){

SubB subObj = new SubB(10,20,30);

subObj.showK();

subObj.sum();

subObj.showXY(); // 子类继承了父类的非私有方法showXY()

}
 }
 (2)类继承传递性
 类继承具有传递性,即子类不仅继承父类的所有非私有成员,也继承
父类的父类直至祖先类所有的非私有成员。另外,通过继承得到的类
还可以有自己的成员。如
 例5.19 类继承传递性的实例程序。

class SuperA{

int x;

private int y ;

SuperA(int x,int y){

this.x = x;

this.y = y;

}

void showXY(){

System.out.println("输出的 x 和 y 分别是: " + x +" " + y );

}
 }

















class SubB extends SuperA{
int total;
SubB(int x,int y){
super(x,y);
}
int sum(){
* total = super.x + super.y; // y在此将不能被访问,它是private的
return total;
}
}
public class InheritanceDemoThree{
public static void main(String args[]){
SubB subObj = new SubB(10,20);
subObj.showXY();
System.out.println("输出的x + y 是: " +subObj.sum());
}
}
 (3)类的成员覆盖
 在类继承中,若子类(派生类)新增的成员名称与
父类(超类)成员相同,则称为成员覆盖
(overriding)。
 子类中定义与父类同名成员的目的是修改父类的
属性和行为,在子类中,通过名称仅能直接访问
本身的成员,若有必要访问父类同名的成员,可
用关键字super。
1. 成员变量的覆盖
 若子类声明了与父类同名的变量,则父类的变量
被隐蔽起来,直接使用的是子类的变量,但父类
的变量仍占据空间,可通过super或父类名来访
问。
 例5.20 成员变量覆盖实例。

class SuperVarClass{

int var = 200;
 }
 class SubVarClass extends SuperVarClass{

int var = 1000;

void display(){

System.out.println("在子类SubVarClass中变量 var = " + var);

System.out.println("在父类SuperVarClass中变量 var = " +
super.var);

}
 }
 public class VarOverridingDemo {

public static void main(String args[]){

SubVarClass subVar = new SubVarClass();

subVar.display();

}
注意:关键字super不能用于静态方法中。
 }
2. 成员方法的覆盖
 Java中,子类可以定义与父类同名的方法,实现对父类
方法的覆盖。但方法成员的覆盖与成员变量的隐藏的不
同之处在于:子类隐藏父类的成员变量只是使得它不可
见,父类的同名成员变量在子类对象中仍占据自己的存
储空间;而子类成员方法对父类成员方法的覆盖将清除
父类方法占据的内存空间,从而使得父类的方法在子类
对象中不存在。
 注意:子类在重新定义父类已有的方法时,应保持与父
类完全相同的方法声明,即应与父类有完全相同的方法
名、返回值和参数列表,否则就不是方法的覆盖,而是
在子类定义自己的与父类无关的成员方法,父类方法将
不会覆盖,会仍然存在。
 适用覆盖方法的规则有:
1. 覆盖方法的返回类型必须与它所覆盖的方
法相同
2. 覆盖方法不能比它所覆盖的方法访问性差
3. 覆盖方法不能比它所覆盖的方法抛出更多
的异常
 子类对父类方法的覆盖也是多态性体现的
一个方面。
 例5.21 成员方法覆盖及this、super应用实例。

class SuperClass { // 定义父类

int x;

SuperClass() { // 父类的构造方法

x=10;

}

void doClass(){

System.out.println("SuperClass.doClass()");

}
 }
 class SubClass extends SuperClass { // 定义子类

int x ;

SubClass() {
// 子类的构造方法

super();
// 调用父类的构造方法

x=100;

}
 void doClass() {
// 重写父类的doClass方法

System.out.println("subClass.doClass()");

}

void doDemo() { // 演示super和this的用法

int x;

x=1000;

super.doClass(); // 调用父类的doClass方法

doClass();
// 调用本类的doClass方法

System.out.println("super.x = " +super.x); // 父类的x

System.out.println("this.x = " + this.x); // 本类的x

System.out.println("x = " +x);
// 本方法的x

}
}
public class SuperDemo{

public static void main(String args[ ])
{ // 主方法

SubClass s=new SubClass();

s.doDemo();

}
}
 (4)派生类初始化
 在创建派生类的对象时,使用派生类的构造方法对
其初始化,不但要对自身的成员变量赋初始值,还
要对父类的成员变量赋初始值。
 Java语言中,子类调用父类构造方法的原则:
1. 在子类的构造方法中,系统会自动添加一条语句:
super();它将调用父类的无参构造方法;若父类中没
有无参构造方法时,会出错。
2. 如父类是有参数的构造方法,子类可以通过在自己
的构造方法中使用super(参数);来调用它,且该语句
必须是子类构造方法的第一个可执行语句。
注意:
在一个类中,静态方法能够直接调用静态
成员变量;而对于实例变量,则必须通过
对象名来调用。
2.抽象类与抽象方法
abstract修饰的抽象类需要子类继承,在子类中
实现抽象类中的抽象方法。抽象类被派生、抽象
方法被子类实现后才有意义。
抽象方法是只有返回值类型、方法名、方法参数
而不定义方法体的一种方法。抽象方法的方法体
在子类中才编写实现。
注意:不能用abstract修饰构造方法、静态方法
和私有方法,也不能覆盖父类中的抽象方法。
抽象方法必须定义在抽象类中。抽象类是一种未
实现的类,抽象类不能用new实例化一个对象。
 例5.22 抽象类与抽象方法应用。
 abstract class Figure{ // 抽象类

double dimX;

double dimY;

Figure(double a,double b){

dimX = a;

dimY = b;

}

abstract double area(); // 抽象方法
}
 class Rectangle extends Figure{

Rectangle(double a,double b){

super(a,b);

}
 double area(){

System.out.println("Inside Area for Rectangle!");

return dimX * dimY;

}
}
 class Triangle extends Figure{

Triangle(double a,double b){

super(a,b);

}

double area(){

System.out.println("Inside Area for Triangle!");

return dimX * dimY / 2;

}
}
 class AbstractAreasDemo{

public static void main(String args[]){

Rectangle r = new Rectangle(10,5);

Triangle t = new Triangle(5,8);

Figure figure;

figure = r;

System.out.println("Area is : " + figure.area());

figure = t;

System.out.println("Area is : " + figure.area());

}
}
 3.类对象之间的类型转换
 Java语言中,有继承关系的父类对象和子类对
象之间也可以在一定条件下相互转换。转换时注
意的原则:
1. 子类对象可以被视为是其父类的一个对象,反之
则不然;
2. 若一个方法的形式参数定义的是父类的对象,则
调用该方法的实际参数可以使用子类对象
3. 若父类对象引用指向的实际是一个子类对象(根
据(1)将子类对象的引用赋给这个父类对象的引
用),则这个父类对象的引用可以用强制类型转
换转化成子类对象的引用。
5.3.2 多态性(polymorphism)
多态性是指,同样的方法对不同类,呈现出不同的
行为。
例如:子类B有一方法op(),它取代了父类A的方法
op(),利用子类B对象实例调用op()方法时,将调
用子类B中的op()方法,而非父类A的方法op()。
子类的对象实例可以代替父类的实例,放置于父类
的对象访问中。面向对象程序的这一性质,与其多
态性密切相关。正因为如此,可以用属于父类的访
问,来调用子类中特有的方法。
常见的多态方式有两种:子类对父类的方法覆盖;
同一个类中定义多个同名的方法,实现方法重载。
1.方法重载
重载是类对自身已有的同名方法的重新定义。
在Java中,同一个类中的两个或两个以上的
方法可以有同一个名字,只要它们的参数声明
不同即可。在这种情况下,该方法就被称为重
载(overload),这个过程称为方法重载。
方法重载是Java实现多态性的一种重要形式
当一个重载方法被调用时,Java用参数的类型、
顺序或数量来表明实际调用的重载方法的版本。
因此,每个重载方法的参数的类型、顺序或数量
必须是不同的。虽然每个重载方法可以有不同的
返回类型,但返回类型并不足以区分所使用的究
竟是哪个方法。
当一个被重载的方法被调用时,Java在调用方法
的参数和方法的形参之间寻找匹配,但是这种匹
配并不总是精确的。在某些情况下,java的自动
类型转换也适用于重载方法的形参。
当重载一个方法时,该方法的每个版本都
能够执行你想要的任何动作。没有什么规
定要求重载方法之间必须相互联系。但是,
从风格上来说,方法重载还是暗示了一种
关系。这就是说当能够使用同一个名字重
载无关的方法时,你不应该这样做。在实
际的程序开发中,应该只重载相互之间关
系紧密的操作。
 【例5.23】实现方法重载的实例。

class OverloadClass{

void testOverload(){

System.out.println("本方法不含任何参数");

}

void testOverload(int a){

System.out.println("本方法含一个int型参数 a = " + a);

}

void testOverload(int x,int y){

System.out.println("本方法含两个int型参数 x = " + x +" y = " + y);

}

double testOverload(double n){

System.out.println("本方法含一个double型参数 n = " + n);

return n * n;

}
 }
 public class OverloadDemo{
 public static void main(String args[]){
 OverloadClass obj = new OverloadClass();
 double result;
 obj.testOverload(); // 调无参的testOverload()方法
 obj.testOverload(20); // 调1个int型参数的testOverload方法
 obj.testOverload(20,30); // 调2个int型参数的testOverload方法
 result = obj.testOverload(16.5);

// 调1个double型参数的testOverload()方法
 System.out.println("调用obj.testOverload(16.5) = " + result);
 }
}
2.动态方法调用
动态方法调用(dynamic method dispatch)是一
种在运行时而不是编译时调用重载方法的机制。
动态方法调用对Java来说是很重要的,是Java实
现运行时多态性的基础。
超类的引用变量可以引用子类对象。Java用这一
事实来解决在运行期间对重载方法的调用,其过
程如下:当一个重载方法通过超类引用被调用时,
Java根据当前被引用对象的类型来决定执行哪个
版本的方法。
注意:这个被调用的方法必须是在超类中定义过
的,也就是说被子类覆盖的方法。
















【例5.24】实现方法动态调度的实例。
class DynamicA{
void callMe(){
System.out.println("Inside DynamicA's callMe() method!");
}
}
class DynamicB extends DynamicA{
void callMe(){
System.out.println("Inside DynamicB's callMe() method!");
}
}
class DynamicC extends DynamicA{
void callMe(){
System.out.println("Inside DynamicC's callMe() method!");
}
}
 public class DynamicDispatchDemo{

public static void main(String args[]){

DynamicA da = new DynamicA();

DynamicB db = new DynamicB();

DynamicC dc = new DynamicC();

DynamicA obj;

obj = da;

obj.callMe();

obj = db;

obj.callMe();

obj = dc;

obj.callMe();

}
 }
JAVA多态性综合示例
class supA{
public int value = 0;
public int f(){return value;}
public String h(){return "sup";}
}
class subB extends supA{
public int value = 1;
public int f(){return value;}
public int g(){return super.value;}
public String h(){return "sub";}
}
 class Test{
 public static void main(String[] args){
 supA a = new supA();
 System.out.println(a.value+","+a.f()+","+a.h());
 supA b = new subB();
 //System.out.println(b.value+","+b.f()+","+b.g()+","+b.h());
 System.out.println(b.value+","+b.f()+","+b.h());
 subB c = new subB();
 System.out.println(c.value+","+c.f()+","+c.g()+","+c.h());
}
}
请给出该程序的运行结果!
 多态性总结
1. 一个类型引用只能引用该类自身含有的方
法和变量
2. 子类对象可以自动转换为父类的对象
3. 一个基类的对象引用,被赋予不同的子类
对象时,执行该方法,将表现出不同的行
为。 运行时,将根据这个对象实际的类
型来动态获取对应的方法,即动态调用。
5.4
接口(interface)
接口是Java语言特点之一,它是若干没有
方法内容的方法体(抽象方法)和常量(隐含
了final与static修饰符)的集合,仅提供了
方法协议的封装。
接口是面向对象的一个重要思想,接口的
使用使得方法的描述说明和方法功能的实
现分开考虑,这有助于降低程序的复杂性,
使程序设计更加灵活,便于扩充。
5.4.1 接口的定义
在Java语言中,接口的声明格式与类相似,接口
关键字用interface来定义。其一般声明格式如下:
 [修饰符] interface 接口名[extends] [接口列表]{

接口体
 }
接口声明包括两个方面内容:定义接口名和接口
体。其中,接口名可以是Java中任意的合法标识
符,接口体同抽象类相似,是变量和抽象方法的
集合,但没有构造方法和静态初始化代码。
【例5.25】一个简单的Countable接口的声明。
 interface Countable{
final int MAXCOUNTER = 50;
void incCount();
void decCount();
int currCount();
int setCount(int newcount)
}
很显然,接口体可以包含成员变量和成员方法,
但与类中定义的成员变量和成员方法有不同之处。
(1) 接口中的成员变量
接口中所有的成员变量都是隐含public、static、
final的,因此接口中的成员变量都是静态最终变
量。
接口中成员变量声明的格式如下:
[修饰符] 类型名 变量名列表;
其中成员变量修饰符是可选的,它只能是public、
static或final。例如,
接口中的如下语句:
int INCREMENT = 3;
等同于
public static final int INCREMENT = 3;
(2) 接口中的方法
接口中说明的方法都是抽象的和公共的,
其声明的格式为:
[修饰符] 返回值类型 方法名(参数列表);
其中,方法修饰符是可选的,它只能是
public或abstract。接口中所有的方法都是
隐含public和abstract的。
5.4.2 接口的实现
一旦接口被定义,一个或多个类可以实现该接口。
接口实现的一般格式如下:
 [修饰符] class 类名 [extends 超类名]
[implements 接口名1[,接口名2[,…]]]{
 …………
 }
这里的修饰符要么是public,要么是缺省访问修饰
符。如果一个类实现多个接口,这些接口被“,”号
分隔。如果一个类实现两个声明了同样方法的接口,
那么相同的方法将被其中任意一个接口用户使用。
实现接口的方法必须声明为public。
















【例5.26】接口声明与实现。
interface InfCircle{ // 定义接口
double r = 10;
double getArea();
double getArcLength();
}
class ImpCircle implements InfCircle{
public double getArea(){ // 必须是public修饰的实现方法
double retArea = Math.PI * r * r;
return retArea;
// 返回类型与在接口中定义时要相同
}
public double getArcLength(){ // 必须是public修饰的实现方法
double retArcLength = 2 * Math.PI * r;
return retArcLength;
// 返回类型与在接口中定义时要相同
}
}
public class InterfaceDemoOne{
public static void main(String args[]){

ImpCircle ir = new ImpCircle();

System.out.println("圆的面积是:" +
ir.getArea());

System.out.println( "圆的周长是:" +
ir.getArcLength() );

}
}
程序执行结果如下
 圆的面积是: 314.1592653589793
 圆的周长是: 62.83185307179586
接口主要的作用如下:
(1)通过接口可以实现不相关类的相同行为,
而不需要了解对象所对应的类。
(2)通过接口可以指明多个类需要实现的方法。
(3)通过接口可以了解对象的交互界面,而不
需了解对象所对应的类。
注意:如果一个类声明实现一个接口,但没有
实现接口中的所有方法,那么这个类必须是抽
象(abstract)类。

















【例5.27】一个没有实现接口中所有方法的抽象类。
interface Computable{
final int MAXSIZE = 100;
void speak(String s);
int f(int x);
float g(float x,float y);
}
abstract class InterfaceDemo implements Computable{
// 方法未完全实现,所以用abstract修饰
public int f(int x){
int sum = 0;
for(int i=1;i<=x;i++){
sum = sum + i;
}
return sum;
}
}
在接口声明时,如果关键字interface前面
加上public关键字时,则称这样的接口是
一个public接口。public接口可以被任何一
个类使用,如果一个接口不加public修饰,
在Java语言中,称这样的接口为友好接口,
友好接口可被同一包中的类来实现。
5.4.3 接口的应用
1.接口继承与组合
接口可以通过关键字extends继承其它接口
(又称接口扩展)。子接口将继承父接口中所
有的常量和抽象方法。此时,子接口的非
抽象派生类不仅需要实现子接口的抽象方
法,还需要实现继承来的方法。不允许存
在未被实现的接口方法。


















【例5.28】 接口的继承实例。
interface InterfaceA{ // 声明接口A
String a = "在接口 A 中";
void showA();
}
interface InterfaceB extends InterfaceA{ // 声明接口B,它继承自A
String b = "在接口 B 中";
void showB();
}
interface InterfaceC extends InterfaceB{ // 声明接口C,它继承自B
String c = "在接口 C 中";
void showC();
}
class InterfaceABC implements InterfaceC{ // 声明实现接口C的类
public void showA() { // 实现public 方法
System.out.println(a);
}















public void showB(){
System.out.println(b);
}
public void showC(){
System.out.println(c);
}
}
public class InterfaceDemoTwo{
public static void main(String args[]){
InterfaceABC myIntf = new InterfaceABC();
myIntf.showA();
myIntf.showB();
myIntf.showC();
}
}
接口继承不允许循环继承或继承自己。接
口与类终究有些方面不同,如所有类的根
类为Object,而接口却没有所谓的共同接
口。一个接口可以同时继承多个接口,还
可以通过extends将多个接口组合成一个接
口。
如下面语句就是将接口A与B组合。
 public interface myAllInterface
extends interfaceA,interfaceB{

Void doSomethingElse(); }
 2.接口的多态
 【例5.29】定义接口并实现接口,说明接口的多态。
 interface OneToN{ int dispResult(int n);}
 class Sum implements OneToN{ // 继承接口

public int dispResult(int n){

// 实现接口中的dispResult()方法

int i,s = 0;

for(i=1;i<=n;i++){ s += i; }

return s;

}
}
 class Pro implements OneToN{ // 继承接口

public int dispResult(int n){

// 实现接口中的dispResult()方法
















int i,m = 1;
for(i=1;i<=n;i++){
m *= i;
}
return m;
}
}
public class InterfaceDemoThree{
public static void main(String args[]){
int n = 10;
Sum s = new Sum();
Pro p = new Pro();
System.out.println("1至n的和 = "+s.dispResult(n));
System.out.println("1至n的积 = "+p.dispResult(n));
}
}
3.接口类型应用(接口回调)
 Java语言中,某些系统类的方法返回值类型为
接口类型,这说明接口可以作为一种类型来使用,
这种操作又称接口回调。实际上接口就是一种引
用类型。
任何实现接口的类的实例都可以存储在该接口类
型的变量中。当我们通过这些引用调用方法时,
在实际引用接口的实例的基础上,方法被正确调
用。这是接口的最显著特性之一。被执行的方法
在运行时动态操作,允许在调用方法代码后创建
类。调用代码在完全不知“调用者”的情况下可
以通过接口来调度。这与用超类引用来访问子类
对象很相似。
















【例5.30】 接口类型应用实例。
interface OneToN{
int dispResult (int n);}
class Sum implements OneToN{
public int dispResult(int n){
int i,s = 0;
for(i=1;i<=n;i++){s += i; }
return s;
}
}
class Pro implements OneToN{
public int dispResult(int n){
int i,m = 1;
for(i=1;i<=n;i++){m *= i; }
return m;
}
}
 public class InterfaceDemoFour{

public static void main(String args[]){

int n = 10;

OneToN otn;

Sum s = new Sum();

otn = s; // 在接口类型变量中存储Sum类的实例

System.out.println("1至n的和 = "+otn.dispResult (n));

Pro p = new Pro();

otn = p; // 在接口类型变量中存储Pro类的实例

System.out.println("1至n的积 = "+otn.dispResult(n));

}
 }
 程序运行结果如下

1至n的和 = 55

1至n的积 = 3628800
5.5
包
5.5.1 包的概述
包是一组相关类和接口的集合。
包体现了Java语言面向对象特性中的封装机制,
包将java语言的类和接口有机地组织成层次结构,
这个层次结构与具体的文件系统的目录树结构层
次一致。
使用包不仅可以避免名字的冲突,还可以将大量
的类按照功能和用途组织起来,访问和查找起来
更加方便,可以提供一定的访问控制。
5.5.2 创建包
通过关键字package来声明包。
形式:
 package 包名;
package语句必须作为Java源文件的第一条
非空格、非注释语句,指明该源文件定义
的类所在的包。
通过package语句,可将Java程序分层次地
存放在不同的目录下,目录名称与包的名
称相同。
如果在源文件中省略了package语句,则源
文件中用户定义命名的类被隐含地认为是
无名包的一部分,即源文件中用户定义命
名的类在同一个包中,但该包没有名字。
尽管默认包对于小的例子程序很好用,但
对于实际的中、大型应用程序,我们需要
为自己的代码定义一个包。
用户可以创建层次包。
多级层次包的通用声明形式如下:
package 包名1[.包名2[.包名3[.[ ...]]]];
在JDK中需手
如下例所示:
动创建相应的
目录结构
【例5.32】 层次包的创建。
package JavaWorkSpace.Example;
public class NumberIsPrime{
public static void main(String args[]){
 int n,j,k,sum = 0;
 for(n=2;n<10;n++){

k = (int)Math.sqrt(n);

for(j=2;j<=k;j++){

if(n%j == 0 )

break;

}

if(j>k)

System.out.println(n+" 是素数!");
 }
 }
}
5.5.3 使用包
将类组织为包的目的是为了更好地利用包中
的类。一般情况下,一个类只能引用与它在
同一个包中的类。
在Java程序中,若要用到某些包中的类或接
口,一种方法是在程序的开始部分写出相应
的引入(import)语句,指出要引入哪些包
的哪些类。另一种方法不用引入语句,直接
在要引入的类和接口前给出其所在包名。无
论采用哪种方法,使用系统类的前提是这个
系统类应该是用户程序可见的类。
1.使用import语句
import语句用于灵活地实现在编译单元中使用外部类
和接口的引入机制,引入语句不必考虑类和接口的
引入顺序和是否被多次引入。
import语句的格式如下:

import 包名;

import 包名.标识符; //引入包中的类和接口

import 包名.*;
//引入包
//引入包中的全部类和接口
2.直接使用包
这种方法一般用在程序中引用类和接口次
数较少的时候,在要引入的类和接口前直
接给出其所在包名。
例如:
java.applet.Applet ap = new java.applet.Applet();
这种逐个引入同一包中的多个类的形式使
用起来非常麻烦。
因此,要使用某个包中的多个类时,可通
过引入的方法来实现。
3.使用CLASSPATH环境变量
CLASSPATH环境变量的作用与DOS的PATH和APPEND命
令作用类似,当一个程序找不到它所需要的其他类
的.class文件时,系统会自动到CLASSPATH环境变量
所指明的路径中去查找。
通过SET命令设置CLASSPATH,可设置程序对类的搜
索路径。若设置错误,Java程序将不能正常执行。
下面是一个设置CLASSPATH的SET命令:
SET CLASSPATH
= .;c:\jdk1.5\lib;c:\jdk1.5\lib\classes.zip
它 将 Java 类 搜 索 路 径 设 置 为 当 前 目 录 、
c:\jdk1.5\lib目录和c:\jdk1.5\lib\classes.zip
Java API(Java 应用程序接口)的主要包。
 java.lang
 java.lang是Java语言的核心包,有Java程序所需要的最基
本的类与接口,包括Object类、基本数据类型包装类、数学
类、异常处理类、线程类、字符串处理类、系统与运行类和
类操作类等。java.lang包由编译器自动引入。
 java.applet
 java.applet包是用来实现运行于Internet浏览器中的Java
Applet的工具类库,其中包含了少量的几个接口和一个非常
有用的类Applet
 java.awt
 java.awt包是Java抽象窗口工具包,其中包含了许多关于字
体和颜色设置、几何绘图、图像显示、图形用户接口操作的
类和接口。
 java.io
 java.io包是Java语言的标准输入/输出类库,其中包含了实
现Java程序与操作系统、外部设备以及其它Java程序做数
据交换所使用的类。
 java.net
 java.net包是Java网络包,主要实现网络功能。
 java.util
 java.util包包含了Java语言中的一些低级的实用工具,如
处理时间的Date类、处理变长数组的Vector类、实现栈和
杂凑表的Stack类和HashTable类等。
 java.awt.event
 java.awt.event包主要包含了用来处理鼠标、键盘等事件
的接口方法。
 javax.swing
 java.swing包包含了以AWT组件为基础第二代GUI设计工
具包组件----Swing组件。该包提供了从按钮到可拆分面板
和表格的所有组件,这些组件均以字母“J”打头命名。
本章小结
面向对象程序设计的三大特性:封装性、
继承性、多态性。
注意区分类与对象的基本概念:
类是对具有相同或相似属性和行为对象的
抽象描述,类是静态概念。
对象是现实世界中实体的描述,对象要创
建后才能使用。
 接口可使设计与实现分离,利用接口的用户程序不受不同
接口实现的影响,不受接口实现改变的影响。接口弥补了
Java只支持单继承的不足,它用来完成多继承的功能。
 包是一组相关类和接口的集合。使用包可以提供一定的访
问控制。类、方法缺省访问权限就是可以在它所属的包中
被访问。说明为public的类、方法才可以在其他包中被访
问。如果类和方法被说明为protected, 则其他包中只有它
的子类才可以访问它们。若一个成员被修饰成private的,
则该成员只能在本类中能访问到。
 另外,若一个类修饰为abstract的,则该类必须要被继承。
若修饰为final的,则该类不能被继承。修饰符abstract和
final不能同时用于对一个类的修饰。
全国高职高专计算机技能型人才培养系列规划教材
www.avceit.cn