11 KiB
数组的定义和使用大多和C是一样的。数组是存放一类数据的一种数据结构。Java中的数组(Array)是一种特殊的对象(通过类实例化),也有特殊的语法结构。在学习Array的时候,请注意其语法,以及与后续类和对象的区别。
1. 声明与使用
1.1. 声明与使用数组
下面这个例子说明了数组的基本使用。
public class ArrayTest {
public static void main(String[] args) {
int[] myList;
myList = new int[2];
myList[0] = 0;
myList[1] = 1;
System.out.println(myList[1]);
myList = new int[3];
System.out.println(myList[1]);
}
}
Java中数组的声明与使用与C类似,int[] myList
定义了一个可以存放int数据类型的数组,但是此时还没有为这个数组分配内存。这一点和C的指针类是,其实myList这个变量叫做引用变量,也和指针类似。
要为myList这个数组分配内存,使用 new int[2]
这种类似的语法。该语法返回一个数组对象的引用地址,数组的容量是2,并赋值给引用变量 myList,然后就可以通过引用变量 myList对数组进行操作了。
可以重复对一个数组引用变量使用new语句分配内存,例如,例子中第6行和第12行。与C不同的是,Java不用对动态分配的内存进行回收。
特别注意这里new的语法结构,后面是数组定义时的类型,大小设置不是圆括号,而是方括号!
1.2. 声明和分配内存在一行中
public class ArrayTest2 {
public static void main(String[] args) {
int[] myList = new int[2];
myList[0] = 0;
myList[1] = 1;
System.out.println(myList[1]);
}
}
1.3. 在声明的同时初始化数组
这个语法结构和C类似:
public class ArrayTest3 {
public static void main(String[] args) {
int[] myList = {1,3,5,7};
System.out.println(myList[1]);
}
}
注意,大括号赋初值的语法只能在数组声明中使用,不能单独使用。
1.4. 数组元素的缺省值
When an array is created, its elements are assigned the default value of
0 for the numeric primitive data types, '\u0000' for char types, and false for boolean types.
2. 数组操作
2.1. 数组对象上的操作
数组本质上是一个对象,因此直接可以在数组的引用变量上对数组进行操作。例如,取得数组的长度:
public class ArrayTest2 {
public static void main(String[] args) {
int[] myList = {1,3,5,7};
System.out.println(myList.length);
}
}
myList 作为一个对象,还有很多实例函数,只需要在IDE中写入这个引用变量,并在后面打一个点,就会出现这个对象的所有操作(可能包括变量、函数和常量)。
有兴趣的可以研究一下这些函数的作用,其实从这些函数名就可以知道大约的作用。
2.2. 数组元素的初始值
When an array is created, its elements are assigned the default value of
0 for the numeric primitive data types, '\u0000' for char types, and false for boolean types.
2.3. 加强的for循环
和C一样,Java数组的下标也是从0开始的;结合数组的长度,可以对数组进行遍历。
public class Test {
public static void main(String[] args) {
int arrayInt[] = { 1, 3, 5, 7 };
for (int i = 0; i < arrayInt.length; i++) {
System.out.println(arrayInt[i]);
}
}
}
Java还提供了一种更方便的for循环:
public class ArrayTest2 {
public static void main(String[] args) {
int[] myList = { 1, 3, 5, 7 };
for (int i : myList) {
System.out.println(i);
}
}
}
这个加强版的for循环例子如上,myList是一个数组(更准确的说是一个数据集),每次取得一个数据集的元素并保存在变量i中(注意这个临时变量i的类型必须和数组中存放数据的类型一致),直到所有的元素被遍历。
注意,这个for循环在以后会大量用到。
2.4. 数组变量是引用变量(指针)
对数组赋值,会改变引用变量的内存指向,这和C的指针是一个概念。
注意:Java中不存在手动回收内存,不存在指针悬空的情况。
2.5. 使用函数来复制数组
可以使用循环来复制数组:
public class Test {
public static void main(String[] args) {
int[] sourceArray = { 2, 3, 1, 5, 10 };
int[] targetArray = new int[sourceArray.length];
for (int i = 0; i < sourceArray.length; i++)
targetArray[i] = sourceArray[i];
}
}
Java在System这个类中提供了一个更加通用的数组复制函数arraycopy
,注意这个函数是静态函数。
public class ArrayTest2 {
public static void main(String[] args) {
int[] myList1 = { 1, 3, 5, 7 };
int[] myList2 = new int[10];
System.arraycopy(myList1, 0, myList2, 0, 3);
for (int i : myList2) {
System.out.println(i);
}
}
}
注意 System.arraycopy 这个函数的参数代表什么意思。
2.6. 数组作为函数参数
public class ArrayTest3 {
public static void main(String[] args) {
int[] iA = { 5, 6, 7, 8 };
System.out.println("The original array:");
printArray(iA);
changeVal(iA);
System.out.println("After change item value in function:");
printArray(iA);
changeArray(iA);
System.out.println("After change array in function:");
printArray(iA);
}
public static void printArray(int[] a) {
for (int i : a) {
System.out.println(i);
}
}
public static void changeVal(int[] a) {
for (int i = 0; i < a.length; i++) {
a[i] = i;
}
}
private static void changeArray(int[] a) {
a = new int[3];
for (int i = 0; i < a.length; i++) {
a[i] = i + 100;
}
}
}
注意:可以在函数中改变数组内部元素的值。
2.7. 对数组元素排序
Arrys这个类中提供对数组进行排序的函数:
public class Test {
public static void main(String[] args) {
double[] numbers = { 6.0, 4.4, 1.9, 2.9, 3.4, 3.5 };
java.util.Arrays.sort(numbers);
for (double item : numbers)
System.out.print(item + " ");
}
}
排序后,数组中的元素按照从小到达排列。
2.8. 数组元素的查找
我们可以使用循环来查找数组中某个元素的位置,其实Java已经给我们提供了一个数组查找的函数binarySearch
。注意这里的binary是指二分法排序,而不是指二进制。如果采用二分法查找,那么数组必须是有序的。如果无法确保数组是有序的,使用前面的java.util.Arrays.sort
函数先对数组进行排序。
public class Test {
public static void main(String[] args) {
int[] list = { 2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79 };
int pos = -1;
pos = java.util.Arrays.binarySearch(list, 11);
System.out.println("Index is " + pos);
}
}
这个函数就是binarySearch,这个函数指使用注意这个函数的使用,前面的一窜java.util.Arrays
不是都指类的名字;最有最后的 Arrays
是类名,而 java.util
是命名空间。通常情况下,可以简单的理解命名空间就是目录的层级关系。
关于java.util.Arrays
这个类还有很多其他函数,可以在IDE中通过输入点(.)查看:
有兴趣的同学可以自己去研究一下。
2.9. 补充
这些内容可能考试不会直接考到,但是会方便你的编程,希望你们可以掌握。
关于String的操作,通常会用到把一个字符串转换成数组。例如一个以空格分隔的字符串,我们希望把每一段切取出来,形成一个数组,这时我们使用:
String string = "AAA BBB CCC";
string.split(" ");
split的参数是一个正则表达式(这个我们可以不用掌握),这里如果字符串是空格分隔,写入一个空格的字符串就可以了,标识拆分的字符串。
函数返回是一个 String[] 类型的数组,你得到的是 {"AAA", "BBB", "CCC" } ,注意,不包含分隔字符串。
相对的,可以使用 join 函数把一个字符串数组以一定的分隔符连接成一个新的字符串。
split 是实例函数,join是静态函数。
3. 读取命令行参数
细心的同学们可能注意到了,在主函数中有一个字符串的数组,这个是做什么的?其实这是传递程序运行是输入的命令行参数设计的,我们看看下面这个例子:
public class Calculator {
/** Main method */
public static void main(String[] args) {
// Check number of strings passed
if (args.length != 3) {
System.out.println("Usage: java Calculator operand1 operator operand2");
System.exit(0);
}
// The result of the operation
int result = 0;
// Determine the operator
switch (args[1].charAt(0)) {
case '+':
result = Integer.parseInt(args[0]) + Integer.parseInt(args[2]);
break;
case '-':
result = Integer.parseInt(args[0]) - Integer.parseInt(args[2]);
break;
case '.':
result = Integer.parseInt(args[0]) * Integer.parseInt(args[2]);
break;
case '/':
result = Integer.parseInt(args[0]) / Integer.parseInt(args[2]);
}
// Display result
System.out.println(args[0] + ' ' + args[1] + ' ' + args[2] + " = " + result);
}
}
主函数void main(String[] args)
中有有一个args 的字符串数组。编译这个程序,然后在命令行下执行,如果不记得命令行中如何编译和运行java,请参考第一章中的内容。
在命令行中运行编译好的代码 java Calculator 1 + 21
其中 java是指虚拟机,后面的 Calculator
是Java编译后的可执行代码;1 + 21
是命令行参数。这个参数会传递给Calculator的主程序,通过main函数的args这个字符串数组解析出来。如同Scanner 对象一样,解析这个数组是按照空格区分的,因此,这个例子中我们得到的args数组是:
数组元素 | 值 | 说明 |
---|---|---|
args[0] | 1 | |
args[1] | + | |
args[2] | 21 |
后面的代码就很简单了。
4. 本章重点
- 掌握数组的申明和使用;
- 掌握增强for循环的使用;
- 理解数组作为函数参数的使用;
- 其他内容均为了解。