友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
Java编程思想第4版[中文版](PDF格式)-第22部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
效,因为new 将对象置于“堆”里。对于这些类型,Java 采纳了与 C 和 C++相同的方法。也就是说,不是用
new 创建变量,而是创建一个并非句柄的“自动”变量。这个变量容纳了具体的值,并置于堆栈中,能够更
高效地存取。
Java 决定了每种主要类型的大小。就象在大多数语言里那样,这些大小并不随着机器结构的变化而变化。这
种大小的不可更改正是 Java 程序具有很强移植能力的原因之一。
主类型 大小 最小值 最大值 封装器类型
boolean 1 位 Boolean
char 16位 Unicode 0 Unicode 2 的 16次方…1 Character
byte 8 位 …128 +127 Byte (注释①)
short 16 位 …2 的15 次方 +2 的 15次方…1 Short (注释①)
int 32位 …2 的 31 次方 +2 的31 次方…1 Integer
long 64位 …2 的63 次方 +2 的63 次方…1 Long
float 32 位 IEEE754 IEEE754 Float
double 64 位 IEEE754 IEEE754 Double
Void Void (注释①)
①:到 Java 1。1 才有,1。0 版没有。
数值类型全都是有符号(正负号)的,所以不必费劲寻找没有符号的类型。
主数据类型也拥有自己的“封装器”(wrapper)类。这意味着假如想让堆内一个非主要对象表示那个主类
型,就要使用对应的封装器。例如:
char c = 'x';
Character C = new Character('c');
也可以直接使用:
Character C = new Character('x');
这样做的原因将在以后的章节里解释。
1。 高精度数字
Java 1。1 增加了两个类,用于进行高精度的计算:BigInteger 和 BigDecimal。尽管它们大致可以划分为
“封装器”类型,但两者都没有对应的“主类型”。
47
…………………………………………………………Page 49……………………………………………………………
这两个类都有自己特殊的“方法”,对应于我们针对主类型执行的操作。也就是说,能对 int或 float做的
事情,对BigInteger 和BigDecimal 一样可以做。只是必须使用方法调用,不能使用运算符。此外,由于牵
涉更多,所以运算速度会慢一些。我们牺牲了速度,但换来了精度。
BigInteger 支持任意精度的整数。也就是说,我们可精确表示任意大小的整数值,同时在运算过程中不会丢
失任何信息。
BigDecimal 支持任意精度的定点数字。例如,可用它进行精确的币值计算。
至于调用这两个类时可选用的构建器和方法,请自行参考联机帮助文档。
2。2。3 Java 的数组
几乎所有程序设计语言都支持数组。在C 和 C++里使用数组是非常危险的,因为那些数组只是内存块。若程
序访问自己内存块以外的数组,或者在初始化之前使用内存(属于常规编程错误),会产生不可预测的后果
(注释②)。
②:在 C++里,应尽量不要使用数组,换用标准模板库(Standard TemplateLibrary)里更安全的容器。
Java 的一项主要设计目标就是安全性。所以在C 和 C++里困扰程序员的许多问题都未在Java 里重复。一个
Java 可以保证被初始化,而且不可在它的范围之外访问。由于系统自动进行范围检查,所以必然要付出一些
代价:针对每个数组,以及在运行期间对索引的校验,都会造成少量的内存开销。但由此换回的是更高的安
全性,以及更高的工作效率。为此付出少许代价是值得的。
创建对象数组时,实际创建的是一个句柄数组。而且每个句柄都会自动初始化成一个特殊值,并带有自己的
关键字:null (空)。一旦Java 看到null,就知道该句柄并未指向一个对象。正式使用前,必须为每个句
柄都分配一个对象。若试图使用依然为null 的一个句柄,就会在运行期报告问题。因此,典型的数组错误在
Java 里就得到了避免。
也可以创建主类型数组。同样地,编译器能够担保对它的初始化,因为会将那个数组的内存划分成零。
数组问题将在以后的章节里详细讨论。
2。3 绝对不要清除对象
在大多数程序设计语言中,变量的“存在时间”(Lifetime )一直是程序员需要着重考虑的问题。变量应持
续多长的时间?如果想清除它,那么何时进行?在变量存在时间上纠缠不清会造成大量的程序错误。在下面
的小节里,将阐示Java 如何帮助我们完成所有清除工作,从而极大了简化了这个问题。
2。3。1 作用域
大多数程序设计语言都提供了“作用域”(Scope)的概念。对于在作用域里定义的名字,作用域同时决定了
它的“可见性”以及“存在时间”。在C,C++和 Java 里,作用域是由花括号的位置决定的。参考下面这个
例子:
{
int x = 12;
/* only x available */
{
int q = 96;
/* both x & q available */
}
/* only x available */
/* q “out of scope” */
}
作为在作用域里定义的一个变量,它只有在那个作用域结束之前才可使用。
在上面的例子中,缩进排版使 Java 代码更易辨读。由于 Java 是一种形式自由的语言,所以额外的空格、制
表位以及回车都不会对结果程序造成影响。
注意尽管在 C 和 C++里是合法的,但在 Java 里不能象下面这样书写代码:
48
…………………………………………………………Page 50……………………………………………………………
{
int x = 12;
{
int x = 96; /* illegal */
}
}
编译器会认为变量 x 已被定义。所以C 和C++能将一个变量“隐藏”在一个更大的作用域里。但这种做法在
Java 里是不允许的,因为Java 的设计者认为这样做使程序产生了混淆。
2。3。2 对象的作用域
Java 对象不具备与主类型一样的存在时间。用 new 关键字创建一个Java 对象的时候,它会超出作用域的范
围之外。所以假若使用下面这段代码:
{
String s = new String(〃a string〃);
} /* 作用域的终点 */
那么句柄 s 会在作用域的终点处消失。然而,s指向的 String 对象依然占据着内存空间。在上面这段代码
里,我们没有办法访问对象,因为指向它的唯一一个句柄已超出了作用域的边界。在后面的章节里,大家还
会继续学习如何在程序运行期间传递和复制对象句柄。
这样造成的结果便是:对于用 new 创建的对象,只要我们愿意,它们就会一直保留下去。这个编程问题在C
和C++里特别突出。看来在C++里遇到的麻烦最大:由于不能从语言获得任何帮助,所以在需要对象的时候,
根本无法确定它们是否可用。而且更麻烦的是,在 C++里,一旦工作完成,必须保证将对象清除。
这样便带来了一个有趣的问题。假如Java 让对象依然故我,怎样才能防止它们大量充斥内存,并最终造成程
序的“凝固”呢。在C++里,这个问题最令程序员头痛。但 Java 以后,情况却发生了改观。Java 有一个特别
的“垃圾收集器”,它会查找用new 创建的所有对象,并辨别其中哪些不再被引用。随后,它会自动释放由
那些闲置对象占据的内存,以便能由新对象使用。这意味着我们根本不必操心内存的回收问题。只需简单地
创建对象,一旦不再需要它们,它们就会自动离去。这样做可防止在 C++里很常见的一个编程问题:由于程
序员忘记释放内存造成的“内存溢出”。
2。4 新建数据类型:类
如果说一切东西都是对象,那么用什么决定一个“类”(Class)的外观与行为呢?换句话说,是什么建立起
了一个对象的“类型”(Type )呢?大家可能猜想有一个名为“type”的关键字。但从历史看来,大多数面
向对象的语言都用关键字“class”表达这样一个意思:“我准备告诉你对象一种新类型的外观”。class 关
键字太常用了,以至于本书许多地方并没有用粗体字或双引号加以强调。在这个关键字的后面,应该跟随新
数据类型的名称。例如:
class ATypeName {/*类主体置于这里}
这样就引入了一种新类型,接下来便可用new 创建这种类型的一个新对象:
ATypeName a = new ATypeName();
在ATypeName 里,类主体只由一条注释构成(星号和斜杠以及其中的内容,本章后面还会详细讲述),所以
并不能对它做太多的事情。事实上,除非为其定义了某些方法,否则根本不能指示它做任何事情。
2。4。1 字段和方法
定义一个类时(我们在 Java 里的全部工作就是定义类、制作那些类的对象以及将消息发给那些对象),可在
自己的类里设置两种类型的元素:数据成员(有时也叫“字段”)以及成员函数(通常叫“方法”)。其
中,数据成员是一种对象(通过它的句柄与其通信),可以为任何类型。它也可以是主类型(并不是句柄)
之一。如果是指向对象的一个句柄,则必须初始化那个句柄,用一种名为“构建器”(第4 章会对此详述)
的特殊函数将其与一个实际对象连接起来(就象早先看到的那样,使用new 关键字)。但若是一种主类型,
则可在类定义位置直接初始化(正如后面会看到的那样,句柄亦可在定义位置初始化)。
49
…………………………………………………………Page 51……………………………………………………………
每个对象都为自己的数据成员保有存储空间;数据成员不会在对象之间共享。下面是定义了一些数据成员的
类示例:
class DataOnly {
int i;
float f;
boolean b;
}
这个类并没有做任何实质性的事情,但我们可创建一个对象:
DataOnly d = new DataOnly();
可将值赋给数据成员,但首先必须知道如何引用一个对象的成员。为达到引用对象成员的目的,首先要写上
对象句柄的名字,再跟随一个点号(句点),再跟随对象内部成员的名字。即“对象句柄。成员”。例如:
d。i = 47;
d。f = 1。1f;
d。b = false;
一个对象也可能包含了另一个对象,而另一个对象里则包含了我们想修改的数据。对于这个问题,只需保持
“连接句点”即可。例如:
myPlane。leftTank。capacity = 100;
除容纳数据之外,DataOnly 类再也不能做更多的事情,因为它没有成员函数(方法)。为正确理解工作原
理,首先必须知道“自变量”和“返回值”的概念。我们马上就会详加解释。
1。 主成员的默认值
若某个主数据类型属于一个类成员,那么即使不明确(显式)进行初始化,也可以保证它们获得一个默认
值。
主类型 默认值
Boolean false
Char 'u0000'(null)
byte (byte)0
short (short)0
int 0
long 0L
float 0。0f
double 0。0d
一旦将变量作为类成员使用,就要特别注意由 Java 分配的默认值。这样做可保证主类型的成员变量肯定得到
了初始化(C++不具备这一功能),可有效遏止多种相关的编程错误。
然而,这种保证却并不适用于“局部”变量——那些变量并非一个类的字段。所以,假若在一个函数定义中
写入下述代码:
int x;
那么x 会得到一些随机值(这与C 和C++是一样的),不会自动初始化成零。我们责任是在正式使用x 前分
配一个适当的值。如果忘记,就会得到一条编译期错误,告诉我们变量可能尚未初始化。这种处理正是 Java
优于C++的表现之一。许多 C++编译器会对变量未初始化发出警告,但在 Java 里却是错误。
2。5 方法、自变量和返回值
迄今为止,我们一直用“函数”(Function )这个词指代一个已命名的子例程。但在Java 里,更常用的一个
词却是“方法”(Method),代表“完成某事的途径”。尽管它们表达的实际是同一个意思,但从现在开
始,本书将一直使用“方法”,而不是“函数”。
Java 的“方法”决定了一个对象能够接收的消息。通过本节的学习,大家会知道方法的定义有多么简单!
方法的基本组成部分包括名字、自变量、返回类型以及主体。下面便是它最基本的形式:
50
…………………………………………………………Page 52……………………………………………………………
返回类型 方法名 ( /* 自变量列表*/ ) {/* 方法主体 */}
返回类型是指调用方法之后返回的数值类型。显然,方法名的作用是对具体的方法进行标识和引用。自变量
列表列出了想传递给方法的信息类型和名称。
Java 的方法只能作为类的一部分创建。只能针对某个对象调用一个方法(注释③),而且那个对象必须能够
执行那个方法调用。若试图为一个对象调用错误的方法,就会在编译期得到一条出错消息。为一个对象调用
方法时,需要先列出对象的名字,在后面跟上一个句点,再跟上方法名以及它的参数列表。亦即“对象名。方
法名(自变量1,自变量2,自变量3。。。)。举个例子来说,假设我们有一个方法名叫f(),它没有自变量,返
回的是类型为int 的一个值。那么,假设有一个名为 a 的对象,可为其调用方法f(),则代码如下:
int x = a。f();
返回值的类型必须兼容 x 的类型。
象这样调用一个方法的行动通常叫作“向对象发送一条消息”。在上面的例子中,消息是f(),而对象是 a。
面向对象的程序设计通常简单地归纳为“向对象发送消息”。
③:正如马上就要学到的那样,“静态”方法可针对类调用,毋需一个对象。
2。5。1 自变量列表
自变量列表规定了我们传送给方法的是什么信息。正如大家或许已猜到的那样,这些信息——如同Java 内其
他任何东西——采用的都是对象的形式。因此,我们必须在自变量列表里指定要传递的对象类型,以及每个
对象的名字。正如在Java 其他地方处理对象时一样,我们实际传递的是“句柄”(注释④)。然而,句柄的
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!