第 4章 对象和类程序是计算机不可缺少的一部分,如何有效地编写程序是人们一直以来最关心的问题,而以怎样的思想来指导程序设计显得更加重要。程序设计方法经历了几个发展阶段,而面向对象程序设计是如今最流行、最高效的程序设计方法。每一种思想和方法都有其自身的概念和相应原理,对象和类是面向对象程序设计中最基本、也是最重要的两个概念。本章主要介绍面向对象程序设计的一些基本概念和原理,重点是如何用
Java语言来表示这些概念。
4.1 面向对象程序设计
要掌握一种新思想、新方法,必须先了解其相关概念。本节主要介绍面向对象的一些相关概念及其相应的描述工具 —— UML,是一些比较抽象的概念,读者在学习的过程中,可以先了解其基本内容,待学完后面相关内容后再回来仔细揣摩和体会,必定能收到良好的效果。
所谓面向对象的方法学,就是使我们分析、设计和实现一个系统的方法尽可能地接近我们认识一个系统的方法。包括:
面向对象的分析( OOA,Object-Oriented Analysis)
面向对象的设计( OOD,Object-Oriented Design)
面向对象的程序设计 (OOP,Object-Oriented Program)
面向对象方法学的核心思想是通过一些基本概念体现出来的。它主要围绕着对象、类、消息、继承性、多态性等基本概念和机制展开。如将,对象,作为一个独立的逻辑单元与现实世界中的客体相对应,用,类,来描述具有相同属性特征和行为方法的一组对象,可利用,继承,来实现具有继承关系的类之间的数据和方法的共享,对象之间以,消息,传递的方式进行,通信,等。下面对面向对象方法学中的部分主要核心概念作简单介绍。
4.1 面向对象程序设计 — 面向对象的概念
1.抽象抽象是人类认识世界的一种方式,它是指从同类型的众多事物中舍弃个别的、非本质的属性和行为,而抽取出共同的、
本质的属性和行为的过程。抽象主要包括事物属性的抽象和行为的抽象两种类型。
属性可用来描述事物在某时刻的状态,常用具体的数据来表示。
行为的抽象也称功能的抽象,即舍弃个别的功能,而抽取共同的功能的过程。
4.1 面向对象程序设计 — 面向对象的概念
2.封装封装是将事物的属性和行为聚集在一起而形成一个完整的逻辑单元的一种机制。利用这种机制可以实现信息的隐藏,外界客体只能通过封装向外界提供的接口才能访问描述事物属性的内部数据。这即有利于客体本身的维护,也有利于保护信息的安全。
在面向对象的程序设计过程中,封装的具体作法就是将描述对象状态的属性和对象固有的行为分别用数据结构和方法来加以描述,并将它们捆绑在一起形成一个可供外界访问的独立的逻辑单元,外界只能通过客体所提供的方法来对其间的数据结构加以访问,而不能直接存取。很明显,封装是实现信息隐藏的有效手段,它尽可能隐蔽对象的内部细节,只保留有限的对外接口,使之与外部发生联系。封装保证了数据的安全性、提高了应用系统的可维护性、也有利于软件的移植与重用。
4.1 面向对象程序设计 — 面向对象的概念
3.对象对象 有两个层次的概念:
现实生活中对象指的是客观世界的实体;
程序中对象就是一组变量和相关方法的集合,其中变量表明对象的状态,方法表明对象所具有的行为。
变量方法
4.1 面向对象程序设计 — 面向对象的概念
4.类
(1).类是描述对象的“基本原型”,它定义一类对象所能拥有的数据和能完成的操作。在面向对象的程序设计中,类是程序的基本单元。
(2).相似的对象可以归并到同一个类中去,就像传统语言中的变量与类型关系一样。
(3).程序中的对象是类的一个实例,是一个软件单元,它由一组结构化的数据和在其上的一组操作构成。
4.1 面向对象程序设计 — 面向对象的概念
……
Car car1;
Car car2;
… …
Car carN;
4.1 面向对象程序设计 — 面向对象的概念
4.类
5.消息一个对象与另一个对象如何协作,共同完成一定功能?对象之间如何相互联系?这一切都依赖于消息的传递来实现。消息是一个对象要求另一个对象实施某项操作的请求,它反映了对象之间的信息通信机制,
是不同的对象之间信息交流的惟一手段。发送消息的对象称为发送者,
接收消息的对象称为接收者。在一条消息中,包含消息的接收者和要求接收者完成某项操作的请求,它只告诉接收者需完成什么,而不指示接收者如何完成,具体的操作过程由接收者自行决定。这样,对象之间就不会相互干扰,保证了系统的模块性。
一个对象可以接收不同形式的消息;同一个消息也可以发送给不同的对象;不同的对象对相同的消息可有不同的解释(这就形成多态性)。
发送者发送消息,接收者通过调用相应的方法响应消息,这个过程不断进行,使得整个应用程序在对象的相互调用过程中完成相应的功能,
得到相应的结果。因此,可以说消息是驱动面向对象程序运转的源泉。
4.1 面向对象程序设计 — 面向对象的概念
6,继承在介绍类的概念时提到,可由已有的类派生出新的类,派生出的新类称为子类,原来的类称为父类,从而构成了类的层次关系,也就是类的继承。继承是类之间的一种常见关 系,它是一种,一般,和
,特殊,的关系。如在 一个学校的人事管理系统中,可定义如下几个类:人员 Person类、学生 Student类和教师 Teacher类,其中 Person
类是 Student类和 Teacher类的父类,而 Student类和 Teacher类是
Personr的子类。它们的关系如图 4.1所示:通过继承,子类继承了母类的属性和行为,在子类中就不用再定义父类中已有的属性和行为了。
如在 Person类中,应该具有姓名、性别、年龄、籍贯、民族等属性和对人信息的修改和打印等行为,它们已被封装在 Person类中,在
Student类和 Teacher类中就不用再定义 Person类中已有的属性和行为了。通过继承,Student类和 Teacher类中已经自动具有了从父类继承下来的属性和行为,而只需在 Student类和 Teacher类中添加其自身所需的属性和行为即可。
4.1 面向对象程序设计 — 面向对象的概念
6,继承
4.1 面向对象程序设计 — 面向对象的概念图 4.1
7,多态在前面介绍消息时提到,不同的对象对相同的消息可有不同的解释,这就形成多态性。其实,简单地讲,多态性表示同一种事物的多种形态。如开拖拉机、开小轿车、开大卡车、开火车、
开摩托艇、开飞机等都是,开,,但作用的对象不同,其具体动作也各不相同。但都表达了一个相同的含义 ----开交通工具,
这也是一种抽象,而且是更高一级的抽象。
多态性是面向对象程序设计的主要精髓之一,在此仅作了简单的提及,后面还将详细介绍。
上述的几个概念中,抽象、封装、继承和多态是面向对象方法学中的四个最基本的概念,人们常常将抽象性、封装性、继承性和多态性称为面向对象的四大特性,只有深入了解了这四大特性,才有可能真正掌握面向对象的方法,才能真正步入面向对象程序设计的殿堂。
4.1 面向对象程序设计 — 面向对象的概念
8,UML静态视图简介
UML是统一建模语言( Unified Modeling Language)的缩写形式。它是一个通用的可视化建模语言,用于对软件进行描述、可视化处理、
构造和建立软件系统制品的文档等。 UML适用于各种软件开发方法、
软件生命周期的各个阶段、各种应用领域以及各种开发工具,是一种总结了以往建模技术的经验并吸收了当今优秀成果的标准建模方法。
UML具有相当广泛的内容,鉴于篇幅的限制,本节打算只介绍其中的稍许部分。
视图是 UML中最核心、最主要的内容。视图分结构视图和动态视图两大类,其中结构视图用于描述系统中的结构成员及其相互关系;动态视图用于描述系统随时间变化的行为。
静态视图是 UML中用得很广泛的一种视图,它是结构视图中的一种。
它之所以被称为静态的是因为它不描述与时间有关的系统行为,只用于描述系统中的结构成员及其相互关系。静态视图主要由类及类之间的相互关系组成,这些相互关系主要包括:关联、聚集和泛化等。
4.1 面向对象程序设计 — 面向对象的概念
8,UML静态视图简介静态视图用类图来实现。在类图中类用矩形框来表示,它的属性和行为分别列在分格中;如果不需要表达详细信息,分格可以省略。一个类可能出现在好几个图中,同一个类的属性和行为可以只在一种图中列出,在其他图中可省略。
关系用类框之间的连线来表示,不同的关系用连线和连线两端的修饰符来区别。
表 4-1是静态视图中经常使用的部分符号及说明,在此列出,以供参考。下面对关联、聚集和泛化分别各举一例,以说明如何绘制这些图。
如在学校里,一个教师( Teacher)可以教授多门课( Course),一门课可由多位教师讲授,因此,存在一个教师授课( TeacherCourse)的关联(如图 4.2所示)。在由界面元素构成的人机界面模型中,框架窗口、菜单、工具条等就形成一种聚集关系(如图 4.3所示)。
4.1 面向对象程序设计 — 面向对象的概念
8,UML静态视图简介
4.1 面向对象程序设计 — 面向对象的概念图 4.2
图 4.3
4.1 编程语言的几个发展阶段
机器语言(如汇编语言)
计算机处理信息的早期语言是所谓的机器语言,这种语言中的指令都是由 0,1组成的序列,称这样的序列为一条机器指令。
如某种计算机的指令为 1011011000000000,它表示让计算机进行一次加法操作;而指令 1011010100000000则表示进行一次减法操作。它们的前八位表示操作码,而后八位表示地址码。
过程语言语言把代码组成叫做过程或函数的块。每个块的目标是完成某个任务,例如,一个 C的源程序就是由若干个书写形式互相独立的函数组成。
面向对象编程面向对象编程主要体现下列三个特性:
1.封装性:将数据和对数据的操作封装在一起。
2.继承:子类可以继承父类的属性和功能。同时又具有子类独特的属性和功能
3.多态,1)操作名称的多态,即有多个操作具有相同的名字;
2)与继承相关的多态,指同一操作被不同类型对象调用可产生不同行为。
Java语言是面向对象语言,它的源程序是由若干个类组成,源文件是扩展名为,java的文本文件
4.2 类
类是组成 Java程序的基本要素。类封装了一类对象的状态和方法。类是用来定义对象的模板。
类的实现包括两部分,类声明和类体。
class People
{ …
}
“class People”叫做类声明;,People” 是类名。
习惯上类名的第一个字母大写,但这不是必须的。
当类名由几个“单词”组合而成时,每个单词的首字母使用大写,如 BeijingTime
2.类体
编写类的目的是为了描述一类事物共有的属性和功能,描述过程由类体来实现。类声明之后的一对大括号,{”、,}”以及它们之间的内容称做类体,大括号之间的内容称做类体的内容。
类体的内容由两部分构:一部分是 变量的定义,用来刻画属性;另一部分是 方法 的定义,用来刻画功能。
class 梯形
{
float 上底,下底,高,laderArea; //变量定义部分
float 计算面积 () //方法定义
{
laderArea=(上底 +下底 )*高 /2.0f;
return laderArea;
}
void 修改高 (float h) //方法定义
{
高 =h;
}
}
3.成员变量和局部变量
我们已经知道类体分为两部分。变量定义部分所定义的变量被称为类 的成员变量。在方法体中定义的变量和方法的参数被称为局部变量。
class People{
int boy;
float[] a;
void f(){
boolean cool;
Workman zhangboy;
}
}
class Workman{
double x;
}
成员变量在整个类内都有效,局部变量只在定义它的方法内有效。
Class MyClass{

Int a;

public void aMethod(int b){

int c;

catch(exception e){

}

}

}
成员变量作用域方法参数作用域局部变量作用域异常处理参数作用域
class Sun{
int distance;
int find(){
int a=12;
distance=a; //合法
return distance;
}
void g(){
int y;
y=a; //非法
}
}
成员变量与它在类体中书写的先后位置无关,但不提倡把成员变量的定义分散地写在方法之间或类体的最后,人们习惯先介绍属性再介绍功能。
成员变量又分为 实例成员变量 (简称实例变量)和 类变量 (也称静态变量),如果成员变量的类型前面加上关键字 static,这样的成员变量称做是类变量或静态变量。
如果局部变量的名字与成员变量的名字相同,则成员变量被隐藏,即这个成员变量在这个方法内暂时失效,
class Tom{
int x=98,y;
void f(){
int x=3;
y=x; //y=?
}
}
如果局部变量的名字与成员变量的名字相同,则成员变量被隐藏。这时如果想在该方法内使用成员变量,必须使用关键字 this。
class 三角形
{ float sideA,sideB,sideC,lengthSum;
void setSide(float sideA,float sideB,float sideC)
{ this.sideA=sideA;
this.sideB=sideB;
this.sideC=sideC;
}
}
this.sideA,this.sideB,this.sideC就分别表示成员变量
sideA,sideB,sideC
4.方法
我们已经知道一个类的类体由两部分组成:
变量的定义和方法的定义。方法的定义包括两部分:方法声明和方法体。
public static int max(int num1,int num2) {
int result;
if (num1 > num2)
result = num1;
else
result = num2;
return result;
}
m o d i f i e r r e t u r n v a l u e t y p e m e t h o d n a m e
f o r m a l
p a r a m e t e r s
r e t u r n v a l u e
m e t h o d
b o d y
m e t h o d
h e a d e r
p a r a m e t e r l i s t
De f i n e a m e t h o d I n v o k e a m e t h o d
int z = max(x,y);
a c t u a l p a r a m e t e r s
( a r g u m e n t s )
方法参数在整个方法内有效,方法内定义的局部变量从它定义的位置之后开始有效。如果局部变量的定义是在一个复合语句中,那么该局部变量的有效范围是该复合语句,即仅在该复合语句中有效,如果局部变量的定义是在一个循环语句中,那么该局部变量的有效范围是该循环语句,即仅在该循环语句中有效,
class A{
void f(){
int m=10,sum=0;
if(m>9){
int z=10; //z仅在该复合语句里有效
z=2*m+z;
}
for(int i=0;i<m;i++){
sum=sum+i; //i仅在该循环语句里有效
}
m=sum; //合法
z=i+sum; //非法
}
}
5.方法重载
方法重载的意思是:一个类中可以有多个方法具有相同的名字,但这些方法的参数必须不同,即或者是参数的个数不同,或者是参数的类型不同。
class Area
{ float getArea(float r)
{ return 3.14f*r*r;
}
double getArea(float x,int y)
{ return x*y;
}
float getArea(int x,float y)
{ return x*y;
}
double getArea(float x,float y,float z)
{ return (x*x+y*y+z*z)*2.0;
}
}
public class AmbiguousOverloading {
public static void main(String[] args) {
System.out.println(max(1,2));
}
public static double max(int num1,double num2) {
if (num1 > num2)
return num1;
else
return num2;
}
public static double max(double num1,int num2) {
if (num1 > num2)
return num1;
else
return num2;
}
}
6.构造方法
构造方法是一种特殊方法,
它的名字必须与它所在的类的名字完全相同,而且没有类型,调用它可以创建类的对象。
构造方法像一般的方法,
可以执行任何操作,但主要是为了进行初始化操作的,例如,初始化对象的数据域。
class Circle {
/** The radius of this circle */
double radius = 1.0;
/** Construct a circle object */
Circle() {
}
/** Construct a circle object */
Circle(double newRadius) {
radius = newRadius;
}
/** Return the area of this circle */
doub le findArea() {
return radius * radius * 3.14159;
}
}
Data field
Method
Constructors
6.构造方法
构造方法也可以重载,从而更易于用不同的初始数据值来构造对象。
一个类可以不声明构造方法,在这种情况下,类中隐含地声明了一个方法体为空的无参构造方法,称为默认构造方法,
只有当类中没有明确声明构造方法时它才会自动生成。
总结构造方法与一般方法的不同:
构造方法必须与所在的类具有相同的名字。
构造方法没有返回类型,甚至连 void也没有。
构造方法的调用是在创建一个对象时使用
new操作符进行的。
有析构方法?
Java提供一种称为垃圾回收( Garbage
Collection)的自动处理机制,能够找出并回收对象不再需要的资源,便于重新分配。
但有时当一个对象被销毁时,有必要进行一些特定的清理工作,通常可调用一种特殊的方法---析构方法来达到目的。
protected void finalize() {/*具体实现 */},
class 梯形
{ float 上底,下底,高 ;
梯形 ()
{ 上底 =60;
下底 =100;
高 =20;
}
梯形 (float x,int y,float h)
{ 上底 =x;
下底 =y;
高 =h;
}
}
7.类方法和实例方法
类中的方法也可分为实例方法和类方法,
方法声明时,方法类型前面不加关键字
static的是实例方法、加关键字 static的是类方法。
构造方法是特殊的方法,不能用 static修饰构造方法。
8.值得注意的问题
对成员变量的操作只能放在方法中
class A{
int a;
a=12;}
实例方法既能操作类变量也能操作实例变量,但类方法只能操作类变量
class A{
int a;
static int b;
void f(int x,int y) { a=x;b=y;}
static void g(int z)
{ b=23;
a=z;
}
}
类中方法可互相调用,但类中的类方法只能调用该类的类方法,不能 调用实例方法。
4.3 对象
类是创建对象的模板。当使用一个类创建了一个对象时,我们也说我们给出了这个类的一个实例。
1.创建对象
创建一个对象包括对象的声明和为对象分配内存两个步骤。
(1).对象的声明。
一般格式为:
类的名字 对象名字 ;
如:
People zhangPing;
(2)为声明的对象分配内存使用 new运算符和类的构造方法为声明的对象分配内存,如果类中没有构造方法,系统会调用默认的构造方法(默认的构造方法是无参数的,你一定还记得构造方法的名字必须和类名相同这一规定)。如:
zhangPing=new People();
(3)对象的内存模型使用例子 1来说明对象的内存模型
class XiyoujiRenwu
{ float height,weight;
String head,ear,hand,foot,mouth;
void speak(String s)
{ System.out.println(s);
}
}
class A
{ public static void main(String args[])
{ XiyoujiRenwu zhubajie; //声明对象
zhubajie=new XiyoujiRenwu(); //为对象分配内存,
//使用 new 运 算 符和默认的构造方法
}
}
声明对象时的内存模型
当用 XiyoujiRenwu类声明一个变量,即对象 zhubajie时,如例子
1中的对象 zhubajie:
XiyoujiRenwu zhubajie;
内存模型如右图所示对象分配内存后的内存模型
当系统见到:
zhubajie=new XiyoujiRenwu();
时,就会做两件事:
① 为 height,weight,head,ear,
mouth,hand,foot各个变量分配内存,即 XiyoujiRenwu类的成员变量被分配内存空间,然后执行构造方法中的语句。
② new运算符在为变量 height,weight,
head,ear,mouth,hand,foot分配内存后,将返回一个 引用 给对象变量 zhubajie。
③ 对象的声明和分配内存可以用一个步骤完成
XiyouJiRenWu zhuBajie=new XiyouJiRenWu();
④ 一个类通过 new运算符可以创建多个不同的对象,
这些对象被分配不同的内存空间,因此改变其中一个对象的状态不会影响其他对象的状态。
注:大多数时候,我们创建一个对象,并将它赋给变量,以后就能用这个变量来引用对象。有时候,一个对象并不需要引用。这时,创建一个对象,但不把它明确地赋给变量,
这样创建的对象称为匿名对象。如:
System.out.println(“zhubajie’s weight=“+new XiyouJiRenWu().weight);
2.使用对象
对象不仅可以操作自己的变量改变状态,
而且还拥有了使用创建它的那个类中的方法的能力,对象通过使用这些方法可以产生一定的行为。
通过使用运算符,.”,对象可以实现对自己的变量访问和方法的调用。
例子 4.3
3.对象的引用和实体
我们已经知道,当用类创建一个对象时,成员变量被分配内存空间,这些内存空间称做该对象的实体或变量,而对象中存放着引用,以确保这些变量由该对象操作使用 。 因此,如果两个对象有相同的引用,那么就具有同样的实体 。
假如使用例子 4.2“Point”类的构造方法创建了两个对象 p1,p2。
p1=new Point(12,16); p2=new Point(6,18);
内存模式如图 4.5。 当使用赋值语句 p1=p2;后,内存模式如图
4.6,表示两个对象具有相同的引用,即指向相同的内存实体 。
OxAB
12
16
p1
OxDD
6
18
p2
OxDD
6
18
p2
OxDD
p1
12
16
垃圾
4.参数传值
当方法被调用时,如果方法有参数,参数必须要实例化,即参数变量必须有具体的值。在 Java中,方法的所有参数都是“传值”的,也就是说,方法中参数变量的值是调用者指定的值的拷贝。例如,如果向方法的 int型参数 x传递一个 int值,那么参数
x得到的值是传递值的拷贝。方法如果改变参数的值,不会影响向参数“传值”的变量的值。
基本数据类型参数的传值
对于基本数据类型的参数,向该参数传递的值的级别不可以高于该参数的级别,比如,不可以向 int型参数传递一个 float值,但可以向 double型参数传递一个 float值。
引用类型参数的传值
Java的引用型数据包括对象、数组和接口。
当参数是引用类型时,“传值”传递的是变量的引用而不是变量所引用的实体。
如果改变参数变量所引用的实体,就会导致原变量的实体发生同样的变化。但是,
改变参数的引用不会影响向其传值的变量的引用。
例子 4.5
main方法所需空间
double y,0.8
People zhang,

f方法所需空间
double y,0.8
People p,
reference 一个 People对象堆
reference
值传递
(值为对象的一个引用)
值传递 (y=0.8)
4.4 static 关键字
用 static修饰的成员变量称为类变量
用 static修饰的方法称为类方法
1.实例变量和类变量的区别
一个类通过使用 new运算符可以创建多个不同的对象,不同的对象的实例变量将被分配不同的内存空间,如果类中的成员变量有类变量,那么所有的对象的这个类变量都分配给相同的一处内存,改变其中一个对象的这个类变量会影响其它对象的这个类变量。
Class Takecare{
static int x;
int y;}
Class A{
Takecare A1=new Takecare();
Takecare A2=new Takecare();
}
Ox325
0
0
A1 x
y OxAB5
A2
0
x
y
1.实例变量和类变量的区别
类变量是和该类创建的所有对象相关联的变量,
改变其中一个对象的这个类变量就同时改变了其它对象的这个类变量。因此,类变量不仅可以通过某个对象访问也可以直接通过类名访问。实例变量仅仅是和相应的对象关联的变量,也就是说,
不同对象的实例变量互不相同,即分配不同的内存空间,改变其中一个对象的实例变量不会影响其它对象的这个实例变量。实例变量可以通过对象访问,不能使用类名访问。
例子 4.7
2,实例方法和类方法的区别
实例方法可以被类创建的任何对象调用执行。
类方法不仅可以被类创建的任何对象调用执行,也可以直接通过类名调用
当类被加载到内存时,类方法就被分配了相应的入口地址,直至程序退出才被取消。这就意思着在任务对象被创建之前类方法已经可以被调用;而实例方法只有到该类的第一个对象被创建时才分配入口地址,才可以被该对象调用。
无论是类方法还是实例方法,方法中的局部变量只有被调用执行时才分配内存空间,方法调用完毕,局部变量将被销毁。
例子 4.8
4.5 this 关键字
this是 Java的一个关键字,可以出现在实例方法和构造方法中,但不可以出现在类方法中 。
1,在构造方法中使用 this
this关键字可以出现在类的构造方法中,代表使用该构造方法所创建的对象 。
class Tom{
int leg;
Tom(int n){
this.cry();
leg=n;
this.cry();
}
void cry(){
System.out.println("我是 Tom,我现在有 "+leg+"条腿 ");
}
public static void main(String args[]){
Tom tom=new Tom(4);
}
}
4.5 this 关键字
2,在实例方法中使用 this
this关键字可以出现在类的实例方法中,代表使用该方法的当前对象 。
我们已经知道,实例方法可以操作成员变量 。 实际上,当成员变量在实例方法中出现时,默认的格式是:
this.成员变量 ;
意思是当前对象的成员变量,如:
class A {
int x;
void f() {
this.x=100;
}
}
this代表使用 f的当前对象。
所以,this.x就表示当前对象的变量 x,当对象调用方法 f
时,将 100赋给该对象的变量 x。因此,当一个对象调用方法时,方法中的成员变量就是指分配给该对象的成员变量。因此,通常情况下,
可以省略成员变量名字前面的,this.”。
class B
{
void f()
{
this.g(); //对象调用方法 f时又调用了方法 g。
}
void g()
{
System.out.println("ok");
}
}
在上述 B类中的方法 f中出现了 this,this代表使用方法 f的当前对象,所以,方法 f的方法体中 this.g()就是当前对象调用方法 g,也就是说,当某个对象调用方法 f过程中,又调用了方法 g。由于这种逻辑关系非常明确,一个方法调用另一个方法时可以省略方法名字前面的,this.”。
3.类方法中不可以使用 this
this不能出现在类方法中,这是因为,
类方法可以通过类名直接调用,这时,
可能还没有任何对象诞生。
4,使用 this区分成员变量和局部变量我们已经知道,成员变量在整个类内有效,局部变量仅在方法内有效 。 在方法体中声明的变量以及方法的参数称作局部变量,方法的参数在整个方法内有效,
方法内定义的局部变量从它定义的位置之后开始有效 。
如果局部变量的名字与成员变量的名字相同,则成员变量被隐藏,即这个成员变量在这个方法内暂时失效 。
这时如果想在该方法内使用成员变量,成员变量前面的,this.”就不可以省略,如:
class 三角形
{
float sideA,sideB,sideC,lengthSum;
void setSide(float sideA,float sideB,float sideC)
{
this.sideA=sideA;
this.sideB=sideB;
this.sideC=sideC;
}
}
this.sideA,this.sideB,this.sideC就分别表示当前对象的成员变量 sideA,sideB,sideC。
4.6 包语句
包是 Java语言中有效地管理类的一个机制,使用包有四个理由:
查找定位类。功能相似的类可以放在同一个包中以便查找定位
避免命名冲突。当类发布给其它人共享时,命名冲突时有发生,可将类放入包中,通过类名来引用。
便于发布软件。包将相关的类组织到一起,可以很容易被分发
保护类。包可以提供对类的保护,允许同一个包中的类访问类中被保护的成员,而外部类则无此权限
通过关键字 package声明包语句。 package 语句作为 Java源文件的第一条语句,指明该源文件定义的类所在的包。 package语句的一般格式为:
package 包名 ;
如果源程序中省略了 package语句,源文件中你定义命名的类被隐含地认为是无名包的一部分,即源文件中定义命名的类在同一个包中,但该 包没有名字。
包名可以是一个合法的标识符,也可以是若干个标识符加,.”分割而成 。
选择一个唯一的包名非常重要,因为 Internet的域名是唯一的,所以
Java建议以 Internet域名的倒序作为包的前辍。假想在一台主机上创建一个名为 mypackage的包,该主机的域名为 prenhall.com,则完整的包名应是 com.prenhall.mypackage。
Java要求包名与文件系统的目录结构一一对应 。
但包的最顶目录不一定是根目录,为了使 Java知道包在文件系统中的地址,必须修改环境变量 classpath,使它指向包所在的目录
classpath=.;c:\book;
只要需要,可以在 classpath中添加任意多个目录 。 classpath中指定的目录顺序就是搜寻类的顺序 。 如果在不同的目录中有两个同名的类,Java使用首先找到的类 。
例子 4.9
com.prenhall.mypackage
4.6.2 import 语句
有两种方式使用包中的类 。
使用类的全称 。 例如,tom.jiafei.PrimNumber,如果在程序中仅调用几次,这是方便的 。
使用 import 语句 。 例如,要导入包 java.swing中的所有类,可以调用,import java.swing.*;”。
使用类库中的类为了能使用 Java提供给我们的类,我们可以使用 import语句来引入包中类。在一个 Java源程序中可以有多个 import
语句,它们必须写在 package语句(假如有 package语句的话)和源文件中类的定义之间。
Java运行平台由所需要的 Java类库和虚拟机组成,这些类库被包含在一个 jre\lib中的压缩文件 rt.jar中,当程序执行时,Java运行平台从类库中加载程序真正使用的类字节码到内存。
例子 4.10
Java为我们提供了大约 130多个包,如:
java.applet 包含所有的实现 Java applet的类
java.awt 包含抽象窗口工具集中的图形,文本,
窗口 GUI类
java.awt.image 包含抽象窗口工具集中的图像处理类
java.lang 包含所有的基本语言类
java.io 包含所有的输入输出类
java.net 包含所有实现网络功能的类
java.until 包含有用的数据类型类
2,使用自定义包中的类我们也可以使用 import 语句引入自定义包中的类 。 如:
import tom.jiafei.*;
我们也可以对单独的一个类进行编译,生成字节码文件然后供其它类使用 。 为了使程序能使用 tom.jiafei包中的类,我们必须在 classpath中指明我们包的位置,
例子 4.11
3,使用无名包中的类我们也可以使用无名包中的类 。 如果一个程序要使用
PrimNumber类,可以将 PrimNumber类的包语句去掉重新编译后将该类的字节码文件存放在当前程序所在的目录中即可编写一个有价值的类是令人高兴的事情,你可以将这样的类打包,形成有价值的,软件产品,,供其他软件开发者使用 。
4,避免类名混淆
Java运行环境总是先到程序所在目录中寻找程序所使用的类,
然后加载到内存 。 如果在当前目录没有发现所需要的类,就到 import语句所指的包中查找 。 如果在当前目录中寻找到了要加载的类,那么程序就不会再加载 import语句引入的同名类 。 如果想使用 import语句引入的同名类,必须明显地写出类的包名,如,tom.jiafei.PrimNumber p=new
tom.jiafei.PrimNumber();”
4.7访问权限
类创建了一个对象之后,该对象可以通过,.”运算符操作自己的变量、使用类中的方法,但对象操作自己的变量和使用类中的方法是有一定限制的。
所谓访问权限是指对象是否可以通过,.”运算符操作自己的变量或通过,.”运算符使用类中的方法。
访问限制修饰符有 private,protected和 public,
都是 Java的关键字,用来修饰成员变量或方法。
类的实例方法总是可以操作该类中的成员;类方法总是可以操作类中的类成员,这与访问权限无关。
1.私有变量和私有方法
用关键字 private修饰的成员变量和方法被称为私有变量和私有方法。
一个类在另外一个类中创建一个对象后,该对象不能访问自己的私有变量和私有方法
对于一个类的私有类变量(静态成员变量),那么在另外一个类中,也不能通过类名来操作这个私有类变量。
对于私有成员变量或方法,只有在本类中创建该类的对象时,这个对象才能访问自己的私有成员变量和类中的私有方法例子 4.14
class Tom{
private float weight;
private float f(float a,float b)
{ …
}
}
class Jerry{
void g(){
Tom cat=new Tom();
cat.weight=23f;//非法
cat.f(3f,4f);//非法
}
}
2,共有变量和共有方法
用 public修饰的成员变量和方法被称为共有变量和共有方法
一个类在另外一个类中创建一个对象后,该对象能访问自己的 public变量和 public方法
对于一个类的 public类变量
(静态成员变量),那么在另外一个类中,也能通过类名来操作这个 public类变量。
class Tom{
public float weight;
public float f(float a,float b)
{ …
}
}
class Jerry{
void g(){
Tom cat=new Tom();
cat.weight=23f;//合法
cat.f(3f,4f);//合法
}
}
3.友好变量和友好方法
不用 private,public,protected修饰符的成员变量和方法被称为友好变量和友好方法。
一个类在另外一个类中创建一个对象后,
如果两个类在同一包中,该对象能访问自己的友好变量和友好方法
对于一个类的友好类变量(静态成员变量),如果两个类在同一包中,那么在另外一个类中,也能通过类名来操作这个友好类变量。
如果你在源文件中用 import语句引入了另外一个包中的类,并用该类创建了一个对象,那么该类的这个对象能否访问自己的友好成员?
class Tom{
float weight;
float f(float a,float b)
{ …
}
}
class Jerry{
void g(){
Tom cat=new Tom();
cat.weight=23f;//合法
cat.f(3f,4f);//合法
}
}
4,受保护的成员变量和方法
用 protected修饰的成员变量和方法被称为受保护的成员变量和受保护的方法
一个类在另外一个类中创建一个对象后,如果两个类在同一包中,该对象能访问自己的 protected
变量和 protected方法
对于一个类的 protected类变量(静态成员变量),
如果两个类在同一包中,那么在另外一个类中,
也能通过类名来操作这个 protected类变量。
在后面学习类的继承时,将讲述 protected和“友好”之间在继承方面的区别。
5,public类与友好类
类声明时,如果关键字 class前面加上 public
关键字,就称这样的是一个 public类,不能用 protected和 private修饰类。
可以在任何另外一个类中,使用 public类创建对象。如果一个类不加 public修饰,就称这样的是一个友好类。那么另外一个类中使用友好类创建对象时,要保证它们是在同一个包中。
4.8类的继承
继承是一种由已有的类创建新类的机制。
利用继承,我们可以先创建一个共有属性的一般类,根据该一般类再创建具有特殊属性的新类,新类继承一般类的状态和行为,并根据需要增加它自己的新的状态和行为。由继承而得到的类称为子类,被继承的类称为父类(超类)。 Java不支持多重继承(子类只能有一个父类)。
1.子类
在类的声明中,通过使用关键字 extends来创建一个类的子类,格式如下,
class 子类名 extends 父类名
{…
}
例如:
class Students extends People
{…
}
如果一个类的声明中没有使用 extends关键字,这个类被系统默认为是 Object的直接子类,Object是 java.lang包中的类。
子类对象的构造过程当用子类的构造方法创建一个子类的对象时,子类的构造方法总是先调用父类的某个构造方法,如果子类的构造方法没有指明使用父类的哪个构造方法,子类就调用父类的不带参数的构造方法。
构造方法链
public class Faculty extends Employee {
public static void main(String[] args) {
new Faculty();
}
public Faculty() {
System.out.println("Faculty's no-arg constructor is invoked");
}
}
class Employee extends Person {
public Employee() {
this("Invoke Employee’s overloaded constructor");
System.out.println("Employee's no-arg constructor is invoked");
}
public Employee(String s) {
System.out.println(s);
}
}
class Person {
public Person() {
System.out.println("Person's no-arg constructor is invoked");
}
}
构造一个类的实例时,将会沿着继承链调用所有父类的构造方法,这叫做构造方法链警告:
public class Apple extends Fruit {
public static void main(String[] args){
Apple apple=new Apple();
}
}
class Fruit {
public Fruit(String name) {
System.out.println("Fruit's constructor is invoked");
}
}
如果一个类设计成子类,最好提供一个无参构造方法以避免程序错误。比如:
子类对象的构造过程子类对象的构造:
1)将子类中声明的成员变量作为子类对象的成员变量
2)父类的成员变量也都分配了内存空间,但只将其中一部分
(能继承的那部分)作为子类对象的成员变量。
子类对象内存示意图如下图,
子类未继承 的成员子类未继承的成员引用子类对象子类继承的成员子类继承的成员子类声明的成员子类声明的成员子类对象的构造过程通过上图,给我们有感觉好象:子类创建对象时似乎浪费了一些内存,因为当用子类创建对象时,父类的成员变量也都分配了内存空间,但只将其中一部分做为子类对象的成员变量,但实际情况并非如此,我们需注意到,子类中还有一部分方法是从父类继承的,
这部分方法却可以操作这部分变量。下面的例子 中,子类对象调用继承的方法操作这些未被子类继承却分配了内存空间的变量。
返回
class A{
private int x=10;
protected double y=12.56;
void f(){
y=y+x;
System.out.printf("x=%d,y=%f\n",x,y);
}
}
class B extends A{
double z=12;
void g(){
z=y+100;
System.out.printf("z=%f\n",z);
}
}
class Example{
public static void main(String args[]){
B b=new B();
b.f(); //调用从父类继承的方法。
b.g(); //调用子类自己声明的方法。
}
}
2.子类的继承性
类有可以有两种重要的成员:成员变量和方法。
子类的成员中有一部分是子类自己声明定义的,
另一部分是从它的父类继承的。
所谓子类继承父类的成员变量作为自己的一个成员变量,就好象它们是在子类中直接声明一样,
可以被子类中自己声明的任何实例方法操作,
所谓子类继承父类的方法作为子类中的一个方法,
就象它们是在子类中直接声明一样,可以被子类中自己声明的任何实例方法调用。
子类和父类在同一包中的继承性
如果子类和父类在同一个包中,那么,子类自然地继承了其父类中不是 private的成员变量作为自己的成员变量,并且也自然地继承了父类中不是 private的方法作为自己的方法,继承的成员或方法的访问权限保持不变。
例子 4.15
子类和父类不在同一包中的继承性
如果子类和父类不在同一个包中,那么,
子类继承了父类的 protected,public成员变量做为子类的成员变量,并且继承了父类的 protected,public方法为子类的方法,继承的成员或方法的访问权限保持不变。如果子类和父类不在同一个包里,子类不能继承父类的友好变量和友好方法。
访问修饰符 protected的进一步说明
一个类 A中的 protected成员变量和方法可以被它的直接子类和间接子类继承,比如 B是 A的子类,C是 B的子类,D又是 C的子类,那么 B,C和 D类都继承了 A的 protected成员变量和方法。如果用 D类在 D本身中创建了一个对象,那么该对象总是可以通过,.”运算符访问继承的或自己定义的 protected变量和
protected方法的,但是,如果在另外一个类中,比如 Other类,
用 D类创建了一个对象 object,该对象通过,.”运算符访问
protected变量和 protected方法的权限如下列( a)、( b)所述。
子类 D的 protected成员变量和方法,如果不是从父类继承来的,
object访问这些 protected成员变量和方法时,只要 Other类和 D类在同一个包中就可以了。 (访问权限 )
如果子类 D的对象的 protected成员变量或 protected方法是从父类继承的,那么就要一直追溯到该 protected成员变量或方法的“祖先”
类,即 A类,如果 Other类和 A类在同一个包中,object对象能访问继承的 protected变量和 protected方法。
方法的访问控制
public protected default private
同类
同包
子类
通用性?
不同情形下访问说明符
3.成员变量的隐藏和方法的重写
子类也可以隐藏继承的成员变量,对于子类可以从父类继承的成员变量,只要子类中定义的成员变量和父类中的成员变量同名时,子类就隐藏了继承的成员变量,
子类通过方法的重写可以隐藏继承的方法,方法重写是指:
子类中定义一个方法,并且这个方法的名字、返回类型、
参数个数和类型与从父类继承的方法完全相同。
例子 4.16
对于子类创建的一个对象,如果子类重写了父类的方法,
则运行时系统调用子类重写的方法,如果子类继承了父类的方法(未重写),那么子类创建的对象也可以调用这个方法,只不过方法产生的行为和父类的相同而已,
例子 4.17
重写父类的方法时,不可以降低方法的访问权限。
4,final关键字
final关键字可以修饰类、成员变量和方法中的参数。
final类不能被继承,即不能有子类。
如果一个方法被修饰为 final方法,则这个方法不能被重写。
如果一个成员变量被修饰为 final的,就是常量,常量必须赋给初值,而且不能再发生变化。
如果方法的参数被修饰为 final的,该参数的值不能被改变。
例子 4.18
4.9对象的上转型对象
我们经常说“老虎是哺乳动物”、“狗是哺乳动物”
等,因为老虎类是哺乳类的子类,但这样说将使老虎失掉老虎类独有的属性和功能,而只具有哺乳类的属性和功能。把老虎说成哺乳动物,就是老虎对象的上转型。
假设 B类是 A类子类或间接子类,当我们用子类 B创建一个对象,并把这个对象的引用放到 A类的对象中时,
A a;
B b=new B();
a=b;
称这个 A类对象,a,是子类对象 b的上转型对象,
对象的上转型对象的实体是子类负责创建的,但上转型对象会失去子类对象的一些属性和功能。
对象对象的上转型对象继承或隐藏的成员变量继承或重写的方法新增的变量新增的方法
上转对象不能操作子类新增的成员变量(失掉了这部分属性);不能使用子类新增的方法(失掉了一些功能)。
上转型对象可以操作子类继承或隐藏成员变量,
也可以使用子类继承的或重写的方法。
上转型对象操作子类继承或重写的方法时,就是通知对应的子类对象去调用这些方法。因此,如果子类重写了父类的某个方法后,对象的上转型对象调用这个方法时,一定是调用了这个重写的方法。
可以将对象的上转型对象再强制转换到一个子类对象,这时,该子类对象又具备了子类所有属性和功能。
不可将父类创建的对象的引用赋值给子类声明的对象。(下转型不行!)
例子 4.19
4.10 多态性
多态性就是指父类的某个方法被其子类重写时,
可以各自产生自己的功能行为,
当一个类有很多子类时,并且这些子类都重写了父类中的某个方法。那么当我们把子类创建的对象的引用放到一个父类的对象中时,就得到了该对象的一个上转型对象,那么这个上转的对象在调用这个方法时就可能具有多种形态,
因为不同的子类在重写父类的方法时可能产生不同的行为。也就是说,不同对象的上转型对象调用同一方法可能产生不同的行为。
例子 4.20
4.11 abstract 类和 abstract方法
用关键字 abstract修饰的类称为 abstract类
(抽象类)。
abstract class A
{ …
}
abstract类有如下特点
和普通的类相比,abstract类可以有 abstract方法
(也可以没有 abstract方法)。对于 abstract方法,
只允许声明,不允许实现,而且不允许使用 final
修饰 abstract方法。
abstract class A
{ abstract int min(int x,int y);
int max(int x,int y)
{ return x>y?x:y;
}
}
abstract类不能用 new运算创建对象对于 abstract类,我们不能使用 new运算符创建该类的对象,需产生其子类,由子类创建对象,如果一个类是 abstract类的子类,它必须具体实现父类的 abstract方法,这就是为什么不允许使用 final
修饰 abstract方法的原因。
一个 abstract类只关心它的子类是否具有某种功能,并不关心功能的具体行为,功能的具体行为由子类负责实现,抽象类中的抽象方法可以强制子类必须给出这些方法的具体实现。
例子 4.22
4.12 super关键字
当子类隐藏了从父类继承的成员变量或重写了父类的某个方法,如果在子类中想使用被隐藏或重写的继承父类的成员变量或方法时,可以使用 super关键字。
1、使用 super调用父类的构造方法
子类不继承父类的构造方法,因此,子类如果想使用父类的构造方法,必须在子类的构造方法中使用,并且必须使用关键字 super来表示,而且 super必须是子类构造方法中的头一条语句。
例子 4.23
如果类里定义了一个或多个构造方法,那么 Java不提供默认的构造方法 (不带参数的构造方法 ),因此,当在父类中定义多个构造方法时,应当包括一个不带参数的构造方法,
以防子类省略 super时出错。
4.12 super关键字
2、使用 super操作被隐藏的成员变量和方法
如果我们在子类中想使用被子类隐藏了的父类的成员变量或方法就可以使用关键字
super。
例子 4.24
4.13接口
Java不支持多继承性,即一个类只能有一个父类。单继承性使得 Java简单,易于管理程序。但不易扩展子类的功能。为了克服单继承的缺点,Java使用了接口,一个类可以实现多个接口。
1.接口的声明与使用
使用关键字 interface来定义一个接口。接口的定义和类的定义很相似,分为接口的声明和接口体。
接口体中包含常量定义和方法定义两部分。接口体中只进行方法的声明,不许提供方法的实现,所以,方法的定义没有方法体,且用分号“;”结尾。如:
interface Printable
{ final int MAX=100;
void add();
float sum(float x,float y);
}
接口的使用
一个类通过使用关键字 implements 声明自己使用一个或多个接口。如果使用多个接口,用逗号隔开接口名。如:
class A implements Printable,Addable
如果一个类使用了某个接口,那么这个类必须实现该接口的所有方法,即为这些方法提供方法体,而且方法的名字、返回类型、参数个数及类型必须与接口中的完全一致。
特别要注意,接口中的方法默认是 public abstract(可省略)方法,所以类在实现接口方法时必须一定要用 public
修饰,而且接口中的常量默认是 public static (可省略)
常量。
如果接口方法的返回类型不是 void型,则在类中实现该接口方法时,方法体至少要有一个 return语句;如是 void型,
可以没有任何语句。
Java提供的接口都在相应的包中,通过引入包可以使用
Java提供的接口。也可以自己定义接口,一个 Java源文件就是由类和接口组成的。
例子 4.25
接口的使用
类实现的接口方法以及接口中的常量可以被类的对象调用,
而且常量也可以用类名或接口名直接调用,因为常量默认声明为 public final static。
用 public修饰的称为 public接口,可以被任何一个类使用。如果不加 public修饰,就称为友好接口,可以被同一个包中的类使用。
如果父类使用了某个接口,那么子类也自然使用了该接口,
子类不必再使用 implements声明自己使用了该接口。
接口可能通过 extends声明一个接口是另一个接口的子接口。
子接口将继承父接口全部的方法和常量。
如果一个类声明实现一个接口,但没有实现接口中所有方法,
那么这个类必须是 abstract类,因为类里含有 abstract方法。
2.理解接口
假如轿车、货车、拖拉机、客车都是抽象类机动车类的子类,为了抽象轿车、客车的“收费”、“空调”功能,需要在机动车类里增加这两个抽象方法,但拖拉机等不需要这两个功能,这样一来,增加机动车类的负担,也迫使拖拉机类实现其不需要的功能。不如将这两个功能单独声明成接口,需要该功能的类就声明实现该接口,各取所需。
接口的思想在于它可以增加很多类都需要实现的功能,使用相同的接口的类之间不一定有继承关系。比如轮船类也需要“收费”功能,可让其实现“收费”接口,但轮船类和机动车类之间并没有什么继承关系。
同一个类也可以实现多个接口。接口只关心是否有这个功能,并不关心功能的具体实现。比如你是一个项目主管,
你要求开发机动车类和轮船类的不同开发小组都要有“收费”功能,你可以要求他们这些类要实现“收费”接口,
即实现接口里的,charge”方法,具体怎么实现你不用关心。如果没有这个接口,不同小组给“收费”方法起的名有可能完全不一样。
例子 4.26
3.接口回调
接口回调是指,可以把实现某一接口的类创建的对象的引用赋给该接口声明的接口变量中 。那么该接口变量就可以调用被类实现的接口中的方法。实际上,当接口变量调用被类实现的接口中的方法时,就是通知相应的对象调用接口的方法,
例子 4.27
4.接口做参数
如果准备给一个方法的参数传递一个数值,
可能希望该方法参数的类型是 double类型,
这样就可以向该参数传递
byte\int\long\float\double类型的数据。
如果一个方法的参数是接口类型,就可以将任何实现该接口的类的实例的引用传递给该接口参数,接口参数就可以回调类实现的接口方法。
例子 4.29
4.14 内部类
类可以有两种重要的成员:成员变量和方法,类还可以有一种成员:内部类
Java支持在一个类中声明另一个类,这样的类称作内部类,而包含内部类的类成为内部类的外嵌类。
内部类的类体中不可以声明类变量和类方法 (static 修饰 )。 外嵌类的类体中可以用内部类声明对象,作为外嵌类的成员 。
例子 4.30
4.15 匿名类
和类有关的匿名类当使用类创建对象时,程序允许我们把类体与对象的创建组合在一起,也就是说,类创建对象时,除了构造方法还有类体,此类体被认为是该类的一个子类去掉类声明后的类体,称作匿名类。匿名类是一个子类,由于无名可用,不能声明对象,但可以直接用匿名类创建对象。如:
new People(){ 类体 }
因为是子类,匿名类当然可以继承父类的方法也可以重写父类的方法,而且它一定是内部类,当然可以访问外嵌类的成员。匿名类的类体不可声明 static成员 (即类成员)
匿名类的主要用途是向方法的参数传值(例子 4.31)
4.15 匿名类
和接口有关的匿名类
Java允许直接用接口名和一个类体创建一个匿名对象,
此类体被认为是实现了接口的类去掉类声明后的类体,称作匿名类,如:
new Computable(){实现接口的匿名类的类体 }
如果某个方法的形参是接口类型,那么可以使用接口名和类体组合创建一个匿名对象传递给方法的形参,但类体必须实现接口中的全部方法。
例子 4.32
4.17 Class类
Class是 java.lang包中的类,该类的实例用来封装对象运行时的状态。当一个类被加载且创建对象时,和该类相关的一个类型为 Calss的对象就会自动创建。 Class类本身不提供构造方法,因此,不能使用 new运算符和构造方法显式地创建一个 Class对象。任何对象调用 getClass()方法都可以获取和该对象相关的一个 Class对象,这个 Class对象调用如下的方法可以获取创建对象的类的有关信息,
String getName() 返回类名
Constructor[] getDeclaredConstructors() 返回类的全部构造方法
Field[] getDeclaredFields() 返回类的全部成员变量
Method[] getDeclaredMethods() 返回类的全部方法例子 4.35
使用 Class实例化一个对象
创建对象最常用的方式就是使用 new运算符和类的构造方法,实际上我们也可以使用 Class对象得到一个类的实例。
为了得到一个类的对象,可以先得到一个和该类相关的
Class对象,做到这一点并不困难,只要使用 Class的类方法
public static Class forName(String className) throws
ClassNotFoundException
就可以返回一个和参数 className指定的类相关的 Class对象。再让这个 Class对象调用
public Object newInstance() throws
InstantiationException,IllegalAccessException
方法就可以得到一个 className类的对象。
例子 4.36
4.18 基本类型的类包装
Java的基本数据类型包括,byte,int、
short,long,float,double,char。 Java
同时也提供了基本数据类型相关的类,实现了对基本数据类型的封装。这些类在
java.lang包中,分别是,Byte,Integer、
Short,Long,Float,Double和 Character
类。
1,Double和 Float类
Double类和 Float类实现了对 double和 float基本型数据的类包装。
可以使用 Double类的构造方法:
Double (double num)
创建一个 Double类型的对象;
使用 Float类的构造方法:
Float (float num)
创建一个 Float类型的对象。
Double对象调用 doubleValue()方法可以返回该对象含有的
double型数据;
Float对象调用 floatValue()方法可以返回该对象含有的 float型数据。
2,Byte,Integer,Short,Long类
下述构造方法分别可以创建 Byte,Integer,Short
和 Long类型的对象:
Byte(byte num)
Integer(int num)
Short(short num)
Long(long num)
Byte,Integer,Short和 Long对象分别调用
byteValue (),intValue(),shortValue ()和
longValue ()方法可以返回该对象含有的基本型数据。
3,Character类
Character类实现了对 char基本型数据的类包装。
可以使用 Character类的构造方法:
Character (char c)
创建一个 Character类型的对象。
Character对象调用 charValue()方法可以返回该对象含有的 char型数据。
Character类还包括一些类方法,见课本 P97
例子 4.37
4.19 反编译和文档生成器使用 SDK提供的反编译器,javap.exe可以将字节码反编译为源码,查看源码类中的 public方法名字和 public成员变量的名字,例如:
javap java.awt.Button
将列出 Button中的 public方法和 public成员变量 。 下列命令
javap –privae java.awt.Button
将列出 Button中的全部方法和成员变量。
使用 SDK提供的 javadoc.exe可以制做源文件类结构的
html格式文档 。
假设 D,\test有源文件,Example.java,用 javadoc生成 Example.java的 html格式文挡:
javadoc Example.java
这时在文件夹 test中将生成若干个 html文挡,查看这些文档可以知道源文件中类的组成结构,如类中的方法和成员变量 。
使用 javadoc时,也可以使用参数 -d指定生成文挡所在的目录,例如,
avadoc –d F:\gxy\book Example.java 返回
4.20 JAR文件
可以使用 jar.exe把一些文件压缩成一个 JAR文件来发布应用程序 。 可以直接用 java解释器执行这个压缩文件 。 如:
java –jar Tom.jar
创建 JAR文件 ( 假设应用程序中有两个类 A,B,A是主类 )
编写清单文件,Mymoon.mf
Mainfest-Version,1.0
Main-Class,A
Created-By,1.4(Sun Microsystems Inc.)
生成 JAR文件
jar cfm Tom.jar Mymoon.mf A.class B.class
2,将类压缩成 JAR文件
可以使用 jar.exe把一些类的字节码文件压缩成一个
JAR文件,然后将这个 JAR文件存放到 Java运行环境扩展中,即 $JavaHome\jre\lib\ext文件夹中 。 这样,其他的程序就可以使用这个 JAR文件中的类来创建对象 。
例子,见课本 P99