大多数真实应用程序都会处理像文件、变量、来自文件的记录或数据库结果集这样的集合。Java 语言有一个复杂的集合框架,可以使用它创建和管理各种类型的对象集合。本节将介绍最常用的集合类并帮助您开始使用它们。
数组
备注:本节的代码示例中的方括号是 Java 数组所需语法的一部分,不是可选元素的指示符。
大多数编程语言都包含 数组 的概念,用数组来保存一组元素,Java 语言也不例外。数组基本来讲是一个相同类型的元素的集合。
可以通过两种方式声明数组:
- 创建一个具有一定大小的数组,这个大小在数组的整个生存期中是固定的。
- 创建一个具有一组初始值的数组。这个集合的大小决定了数组的大小 — 它的大小恰好够容纳所有这些值,而且它的大小在数组的整个生存期中是固定的。
声明一个数组
一般而言,可以像这样声明一个数组:
new elementType [arraySize]
可以通过两种方式创建一个整数元素数组。这条语句将创建一个拥有 5 个元素的空间的数组,但它是空的:
// creates an empty array of 5 elements:
int[] integers = new int[5];
这条语句创建该数组并一次性初始化它:
// creates an array of 5 elements with values:
int[] integers = new int[] { 1, 2, 3, 4, 5 };
或
// creates an array of 5 elements with values (without the new operator):
int[] integers = { 1, 2, 3, 4, 5 };
初始值放在花括号内,用逗号分隔。
另一种创建数组的方法是先创建它,然后编写一个循环来初始化它:
int[] integers = new int[5];
for (int aa = 0; aa < integers.length; aa++) {
integers[aa] = aa+1;
}
前面的代码声明了一个可容纳 5 个元素的整数数组。如果尝试在该数组中放入多于 5 个元素,Java 运行时将会抛出一个 异常 。您将在第 2 部分 中了解异常和如何处理它们。
加载数组
要加载数组,需要循环从 1 一直到数组长度的整数(可以在数组上调用 .length
来获取它的长度 — 稍后会更详细地介绍相关内容)。在本例中,循环在到达 5 时停止。
加载数组后,可以像之前一样访问它:
Logger l = Logger.getLogger("Test");
for (int aa = 0; aa < integers.length; aa++) {
l.info("This little integer's value is: " + integers[aa]);
}
此语法也是有效的,而且(因为它更容易使用)本节将全部使用此语法:
Logger l = Logger.getLogger("Test");
for (int i : integers) {
l.info("This little integer's value is: " + i);
}
元素索引
可将数组想成一系列的桶,每个桶中放入一个某种类型的元素。每个桶通过一个元素 索引 来访问:
element = arrayName [elementIndex];
要访问一个元素,需要数组的引用(它的名称)和包含您想要访问的元素的索引。
length 属性
每个数组都有一个 length
属性,该属性具有 public
可视性,可用于确定可将多少个元素放入该数组中。要访问此属性,可使用数组引用、一个句点 (.) 和关键字 length,就象这样:
int arraySize = arrayName.length;
Java 语言中的数组 从 0 开始建立索引 。也就是说,对于所有数组,数组中的第一个元素始终位于 arrayName_ [0]
,最后一个元素位于 arrayName_ [_arrayName_.length - 1]
。
一个对象数组
您已看到数组如何容纳原语类型,但值得一提的是,它们也可以容纳对象。创建一个 java.lang.Integer
对象数组与创建一个原语类型数组没有太多区别,可通过两种方式来创建它:
// creates an empty array of 5 elements:
Integer[] integers = new Integer[5];
// creates an array of 5 elements with values:
Integer[] integers = new Integer[] {
Integer.valueOf(1),
Integer.valueOf(2),
Integer.valueOf(3),
Integer.valueOf(4),
Integer.valueOf(5)
};
装箱和拆箱
Java 语言中的每种原语类型都有一个对应的 JDK 类,如表 4 所示。
表 4. 原语和对应的 JDK 类
原语 | 对应的 JDK 类 |
---|---|
boolean | java.lang.Boolean |
byte | java.lang.Byte |
char | java.lang.Character |
short | java.lang.Short |
int | java.lang.Integer |
long | java.lang.Long |
float | java.lang.Float |
double | java.lang.Double |
每个 JDK 类都提供了相应方法来解析它的内部表示,并将其转换为相应的原语类型。例如,下面这段代码将十进制值 238 转换为一个 Integer
:
int value = 238;
Integer boxedValue = Integer.valueOf(value);
此技术称为 装箱 ,因为您将原语放在一个包装器或箱子中。
类似地,要将 Integer
表示转换为对应的 int
类,可以对它进行 拆箱 :
Integer boxedValue = Integer.valueOf(238);
int intValue = boxedValue.intValue();
自动装箱和自动拆箱
严格来讲,不需要显式对原语进行装箱和拆箱。可以使用 Java 语言的自动装箱和自动拆箱特性:
int intValue = 238;
Integer boxedValue = intValue;
//
intValue = boxedValue;
但是,建议避免使用自动装箱和自动拆箱,因为它们可能导致代码可读性问题。装箱和拆箱代码段中的代码比自动装箱的代码更一目了然,因此更容易阅读;为此投入额外的工作是值得的。
解析和转换装箱的类型
您已经了解了如何获取一个装箱的类型,但如何才能将一个您怀疑拥有装箱类型的数字 String
解析到它的正确箱子中呢?JDK 包装器类也拥有实现此目标的方法:
String characterNumeric = "238";
Integer convertedValue = Integer.parseInt(characterNumeric);
还可以将 JDK 包装器类型的内容转换为 String
:
Integer boxedValue = Integer.valueOf(238);
String characterNumeric = boxedValue.toString();
请注意,在 String
表达式中使用串联运算符时(您已在对 Logger
的调用中看到过),原语类型已自动装箱,而且包装器类型会自动在它们之上调用 toString()
。非常方便。
List
List
是一种有序集合,也称为 序列 。因为 List
是有序的,所以您能够完全控制将列表项放入 List
中的何处。Java List
集合只能包含对象(不能包含像 int
这样的原语类型),而且它为其行为方式定义了严格的契约。
List
是一个接口,所以不能直接将其实例化。(您将在第 2 部分 中了解接口。)这里将使用它的最常用实现 ArrayList
。可通过两种方式声明它。第一种方式使用了显式语法:
List<String> listOfStrings = new ArrayList<String>();
第二种方式使用了”菱形”运算符(在 JDK 7 中引入):
List<String> listOfStrings = new ArrayList<>();
注意, ArrayList
实例化过程中没有指定对象类型。这是因为表达式右侧的类的类型必须与左侧的类型匹配。在本教程的剩余部分中,两种类型都会用到,因为您可能在实践中看到这两种用法。
注意,我将 ArrayList
对象赋给了一个 List
类型的变量。在 Java 编程中,可以将一种类型的变量赋给另一种类型的变量,只要被赋值的变量是赋值变量所实现的超类或接口。在后面的一节中,将进一步介绍这些变量赋值类型的约束规则。
正式类型
前面的代码段中的 <Object>
称为 正式类型 。<Object>
告诉编译器,这个 List
包含一个 Object
类型的集合,这意味着您可以将喜欢的任何实体放在 List
中。
如果您想对能或不能放入 List
中的实体施加更严格的限制,可通过不同方式定义该正式类型:
List<Person> listOfPersons = new ArrayList<Person>();
现在,您的 List
只能包含 Person
实例。
使用 List
使用 List
— 通常像使用 Java 集合一样 — 非常容易。以下是可对 List
执行的一些操作:
- 在
List
中放入列表项。 - 询问
List
目前有多大。 - 从
List
中获取列表项。
要将列表项放在 List
中,请调用 add()
方法:
List<Integer> listOfIntegers = new ArrayList<>();
listOfIntegers.add(Integer.valueOf(238));
add()
方法将元素添加到 List
的末尾。
要询问 List
有多大,请调用 size()
:
List<Integer> listOfIntegers = new ArrayList<>();
listOfIntegers.add(Integer.valueOf(238));
Logger l = Logger.getLogger("Test");
l.info("Current List size: " + listOfIntegers.size());
要从 List
中检索某个项,请调用 get()
并向它传递您想要的项的索引:
List<Integer> listOfIntegers = new ArrayList<>();
listOfIntegers.add(Integer.valueOf(238));
Logger l = Logger.getLogger("Test");
l.info("Item at index 0 is: " listOfIntegers.get(0));
在真实的应用程序中,List
将包含记录或业务对象,您可能想要在处理过程中查看所有这些对象。如何以通用方式实现该目标?答案:您想要 迭代 该集合,可以这么做是因为 List
实现了 java.lang.Iterable
接口。
Iterable
如果一个集合实现了 java.lang.Iterable
,那么它称为 迭代变量集合 。您可从一端开始,逐项地处理集合,直到处理完所有项。
在循环 部分,我简要提及了对实现 Iterable
接口的集合进行迭代的特殊语法。这里将更详细地介绍该语法:
for (objectType varName : collectionReference) {
// Start using objectType (via varName) right away...
}
之前的代码比较抽象,这是一个更切合实际的示例:
List<Integer> listOfIntegers = obtainSomehow();
Logger l = Logger.getLogger("Test");
for (Integer i : listOfIntegers) {
l.info("Integer value is : " + i);
}
这个小代码段所做的事情与下面这个长代码段所做事情相同:
List<Integer> listOfIntegers = obtainSomehow();
Logger l = Logger.getLogger("Test");
for (int aa = 0; aa < listOfIntegers.size(); aa++) {
Integer I = listOfIntegers.get(aa);
l.info("Integer value is : " + i);
}
第一个代码段使用了简写语法:它没有 index
变量(在本例中为 aa
)要初始化,也没有调用 List
的 get()
方法。
因为 List
扩展了 java.util.Collection
(它实现了 可迭代
),所以可以使用简写语法来迭代任何 List
。
Set
Set
是一种集合构造,根据定义,它包含唯一的元素 — 即没有重复项。List
可包含同一个对象数百次,而 Set
只能包含某个特定实例一次。Java Set
集合只能包含对象,而且它为其行为方式定义了严格的契约。
因为 Set
是一个接口,所以您不能直接将其实例化。我最喜欢的实现之一是 HashSet
,它易于使用且类似于 List
。
以下是可对 Set
执行的一些操作:
- 在
Set
中放入内容。 - 询问
Set
目前有多大。 - 从
Set
中获取内容。
Set
的一个独特特征是,它可保证其元素的唯一性,但不关心元素的顺序。考虑以下代码:
Set<Integer> setOfIntegers = new HashSet<Integer>();
setOfIntegers.add(Integer.valueOf(10));
setOfIntegers.add(Integer.valueOf(11));
setOfIntegers.add(Integer.valueOf(10));
for (Integer i : setOfIntegers) {
l.info("Integer value is: " + i);
}
您可能认为该 Set
中有 3 个元素,但它仅有两个,因为包含值 10
的 Integer
对象仅添加了一次。
请在迭代 Set
时注意此行为,如下所示:
Set<Integer> setOfIntegers = new HashSet();
setOfIntegers.add(Integer.valueOf(10));
setOfIntegers.add(Integer.valueOf(20));
setOfIntegers.add(Integer.valueOf(30));
setOfIntegers.add(Integer.valueOf(40));
setOfIntegers.add(Integer.valueOf(50));
Logger l = Logger.getLogger("Test");
for (Integer i : setOfIntegers) {
l.info("Integer value is : " + i);
}