按键盘上方向键 ← 或 → 可快速上下翻页,按键盘上的 Enter 键可回到本书目录页,按键盘上方向键 ↑ 可回到本页顶部!
————未阅读完?加入书签已便下次继续阅读!
C++的矢量类知道自己容纳的是什么类型的对象,但同 Java 的数组相比,它却有一个明显的缺点:C++矢量类
的operator''不能进行范围检查,所以很容易超出边界(然而,它可以查询 vector 有多大,而且at()方法
确实能进行范围检查)。在Java 中,无论使用的是数组还是集合,都会进行范围检查——若超过边界,就会
获得一个RuntimeException (运行期违例)错误。正如大家在第9 章会学到的那样,这类违例指出的是一个
程序员错误,所以不需要在代码中检查它。在另一方面,由于 C++的vector 不进行范围检查,所以访问速度
较快——在 Java 中,由于对数组和集合都要进行范围检查,所以对性能有一定的影响。
本章还要学习另外几种常见的集合类:Vector (矢量)、Stack (堆栈)以及Hashtable (散列表)。这些类
都涉及对对象的处理——好象它们没有特定的类型。换言之,它们将其当作 Object 类型处理(Object 类型
是Java 中所有类的“根”类)。从某个角度看,这种处理方法是非常合理的:我们仅需构建一个集合,然后
任何Java 对象都可以进入那个集合(除基本数据类型外——可用Java 的基本类型封装类将其作为常数置入
集合,或者将其封装到自己的类内,作为可以变化的值使用)。这再一次反映了数组优于常规集合:创建一
个数组时,可令其容纳一种特定的类型。这意味着可进行编译期类型检查,预防自己设置了错误的类型,或
者错误指定了准备提取的类型。当然,在编译期或者运行期,Java 会防止我们将不当的消息发给一个对象。
所以我们不必考虑自己的哪种做法更加危险,只要编译器能及时地指出错误,同时在运行期间加快速度,目
的也就达到了。此外,用户很少会对一次违例事件感到非常惊讶的。
考虑到执行效率和类型检查,应尽可能地采用数组。然而,当我们试图解决一个更常规的问题时,数组的局
限也可能显得非常明显。在研究过数组以后,本章剩余的部分将把重点放到Java 提供的集合类身上。
8。1。1 数组和第一类对象
无论使用的数组属于什么类型,数组标识符实际都是指向真实对象的一个句柄。那些对象本身是在内存
“堆”里创建的。堆对象既可“隐式”创建(即默认产生),亦可“显式”创建(即明确指定,用一个new
表达式)。堆对象的一部分(实际是我们能访问的唯一字段或方法)是只读的 length (长度)成员,它告诉
我们那个数组对象里最多能容纳多少元素。对于数组对象,“''”语法是我们能采用的唯一另类访问方法。
下面这个例子展示了对数组进行初始化的不同方式,以及如何将数组句柄分配给不同的数组对象。它也揭示
209
…………………………………………………………Page 211……………………………………………………………
出对象数组和基本数据类型数组在使用方法上几乎是完全一致的。唯一的差别在于对象数组容纳的是句柄,
而基本数据类型数组容纳的是具体的数值(若在执行此程序时遇到困难,请参考第3 章的“赋值”小节):
//: ArraySize。java
// Initialization & re…assignment of arrays
package c08;
class Weeble {} // A small mythical creature
public class ArraySize {
public static void main(String'' args) {
// Arrays of objects:
Weeble'' a; // Null handle
Weeble'' b = new Weeble'5'; // Null handles
Weeble'' c = new Weeble'4';
for(int i = 0; i 《 c。length; i++)
c'i' = new Weeble();
Weeble'' d = {
new Weeble(); new Weeble(); new Weeble()
};
// pile error: variable a not initialized:
//!System。out。println(〃a。length=〃 + a。length);
System。out。println(〃b。length = 〃 + b。length);
// The handles inside the array are
// automatically initialized to null:
for(int i = 0; i 《 b。length; i++)
System。out。println(〃b'〃 + i + 〃'=〃 + b'i');
System。out。println(〃c。length = 〃 + c。length);
System。out。println(〃d。length = 〃 + d。length);
a = d;
System。out。println(〃a。length = 〃 + a。length);
// Java 1。1 initialization syntax:
a = new Weeble'' {
new Weeble(); new Weeble()
};
System。out。println(〃a。length = 〃 + a。length);
// Arrays of primitives:
int'' e; // Null handle
int'' f = new int'5';
int'' g = new int'4';
for(int i = 0; i 《 g。length; i++)
g'i' = i*i;
int'' h = { 11; 47; 93 };
// pile error: variable e not initialized:
//!System。out。println(〃e。length=〃 + e。length);
System。out。println(〃f。length = 〃 + f。length);
// The primitives inside the array are
// automatically initialized to zero:
for(int i = 0; i 《 f。length; i++)
System。out。println(〃f'〃 + i + 〃'=〃 + f'i');
System。out。println(〃g。length = 〃 + g。length);
210
…………………………………………………………Page 212……………………………………………………………
System。out。println(〃h。length = 〃 + h。length);
e = h;
System。out。println(〃e。length = 〃 + e。length);
// Java 1。1 initialization syntax:
e = new int'' { 1; 2 };
System。out。println(〃e。length = 〃 + e。length);
}
} ///:~
Here’s the output from the program:
b。length = 5
b'0'=null
b'1'=null
b'2'=null
b'3'=null
b'4'=null
c。length = 4
d。length = 3
a。length = 3
a。length = 2
f。length = 5
f'0'=0
f'1'=0
f'2'=0
f'3'=0
f'4'=0
g。length = 4
h。length = 3
e。length = 3
e。length = 2
其中,数组 a 只是初始化成一个 null 句柄。此时,编译器会禁止我们对这个句柄作任何实际操作,除非已正
确地初始化了它。数组 b 被初始化成指向由 Weeble 句柄构成的一个数组,但那个数组里实际并未放置任何
Weeble 对象。然而,我们仍然可以查询那个数组的大小,因为 b 指向的是一个合法对象。这也为我们带来了
一个难题:不可知道那个数组里实际包含了多少个元素,因为 length 只告诉我们可将多少元素置入那个数
组。换言之,我们只知道数组对象的大小或容量,不知其实际容纳了多少个元素。尽管如此,由于数组对象
在创建之初会自动初始化成null,所以可检查它是否为 null,判断一个特定的数组“空位”是否容纳一个对
象。类似地,由基本数据类型构成的数组会自动初始化成零(针对数值类型)、null (字符类型)或者
false (布尔类型)。
数组c 显示出我们首先创建一个数组对象,再将Weeble 对象赋给那个数组的所有“空位”。数组 d 揭示出
“集合初始化”语法,从而创建数组对象(用new 命令明确进行,类似于数组c),然后用Weeble 对象进行
初始化,全部工作在一条语句里完成。
下面这个表达式:
a = d;