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