数组
数组的定义:
数组是一种数据结构,用来存储同一类型值的集合。通过整型下标可以访问数组中的每一个值。
数组是 Java 中很重要的数据结构,那么我们如何使用数组呢?
首先应该声明数组,例如,下面声明了整型数组 a :
int[] a;
不过,这条语句只声明了变量 a ,并没有将 a 初始化为一个真正的数组。应该使用 new 运算符创建数组:
int[] a = new int[100];
这条语句创建了一个可以存储 100 个整数的数组。
注意: 数组长度不要求是常量: new int[n] 会创建一个长度为 n 的数组。
一旦创建了数组,就可以给数组元素赋值。例如,使用一个循环:
for(int i = 0; i < 100; i++){
a[i] = i;
}
创建一个数字数组时,所有元素都初始化为 0;boolean 数组的元素会初始化为 false 。对象数组的元素会初始化为一个特殊值 null,这表明这些元素还未存放任何对象。不懂? 看下面这个例子:
String[] names = new String[10];
字符串 String 在 Java 中是一个预定义类,所以称上面这个数组是对象数组是毫无疑问的。这行代码会创建一个包含 10 个字符串的数组,所有的字符串都为 null。是 null!而不是 空串 。当然,如果你希望这个数组包含空串,可以为元素指定空串:
for(int i = 0; i < a.length; i++){
names[i] = "";
}
如果你想要获得数组中元素的个数,可以使用 array.length 。例如:
for(int i = 0; i < a.length; i++){
System.out.println(a[i]);
}
一旦创建了数组,就不能再改变它的大小(尽管可以改变每一个数组元素)。如果经常需要在运行过程中扩展数组的大小,就应该使用另一种数据结构——数组列表(array list)。今天我们不探讨它。
Java 的 for each 循环
for each 是一种很强大的循环结构,可以用来依次处理数组中的每一个元素(其他类型的元素集合亦可)而不必为指定下标值而分心。语句格式如下:
for (variable : collection) statement
定义一个变量用于暂存集合中每一个元素,并执行相应的语句或语句块。collection 这一集合表达式必须是一个数组或者是一个实现了 Iterable 接口的类对象(例如 ArrayList )。举例:
for(int element : a){
System.out.println(element);
}
当然,使用 for 循环也可以达到相同的效果。但是,for each 循环语句显得更加简洁,更不容易出错。
提示: 有个更简单的方式打印数组中的所有值,即利用 Arrays 类的 toString 方法。返回的是包含数组元素的字符串,这些元素被放置在括号内,并用逗号分隔,例如,“[2,3,5,7]” 。我至今还没用过,如果好奇,请自行尝试。
数组初始化以及匿名数组
代码
int[] smallPrimes = {1,3,5,7,9,11};
是没有问题的。而且,在使用这种语句是不需要调用 new。
我们甚至可以通过这种方法初始化一个匿名的数组:
new int[] {10,23,44,12,23,23} //代码不完整
这种表示法将创建一个新数组并利用括号中提供的值进行初始化,数组的大小就是初始值的个数。
使用这种语法形式可以在不创建新变量的情况下重新初始化一个数组。例如:
smallPrimes = new int[] {10,23,44,12,23,23};
这是下列语句的简写形式:
int[] anonymous = {10,23,44,12,23,23};
smallPrimes = anonymous;
数组拷贝
将一个数组变量拷贝给另一个数组变量 ,这时,两个变量将引用同一个数组:
int[] luckyNumbers = smallPrimes;
luckyNumbers[5] = 12; // now smallPrimes[5] is also 12
改了一个就改了另一个,这是一种荣辱与共的关系。
如果希望将一个数组的所有值拷贝到一个新的数组中去,就要使用 Arrays 类的 copyOf 方法:
int[] copiedLuckyNumbers = Arrays.copyOf(luckyNumbers, luckyNumbers.length);
这个方法的第二个参数是新数组的长度,可以自行定义。
如果数组元素是数值型,那么多余的元素将被赋值为 0 ;如果数组元素是布尔型,则将赋值为 false。当然,如果长度小于原始数组的长度,则只拷贝最前面的数据元素。
数组排序
使用 Arrays 类的 sort 方法可以对数值型数组进行排序:
int[] a = new int[10000];
...
Arrays.sort(a);
这个方法使用了优化的快速排序算法,对大多数数据集合来说都是效率比较高的。
我们来看下面这个程序,它产生了一个抽彩游戏中随机数值组合:
import java.util.*;
public class HelloWorld {
public static void main(String[] args) {
Scanner in = new Scanner(System.in);
System.out.print("How many numbers do you need to draw? ");
int k = in.nextInt();
System.out.print("What's the highest number you can draw? ");
int n = in.nextInt();
int[] numbers = new int[n];
for(int i = 0; i < numbers.length; i++) {
numbers[i] = i + 1;
}
int[] result = new int[k];
for(int i = 0; i < result.length; i++) {
int r = (int)(Math.random() * n);
result[i] = numbers[r];
numbers[r] = numbers[n-1];
n--;
}
Arrays.sort(result);
System.out.println("Bet the following combination. It'll make you rich!");
for(int r : result)
System.out.println(r);
}
}
运行结果截图:
多维数组
多维数组将使用多个下标访问数组元素,它适用于表示表格或更加复杂的排列形式。
例如,表示表格可以用二维数组(也称为矩阵)。
我们来声明一个二维数组:
double[][] balances;
然后我们来初始化:
balances = new double[NYEARS][NYATES];
当然可以换一种方式,例如:
int[][] magicSquare =
{
{16,2,3},
{5,10,11},
{9,6,7},
{23,1,2}
};
思考下面这个不完整的代码(一个存储余额的二维数组 balances,一维表示年,另一维表示利率,最初使用初始余额来初始化这个数组的第一行):
for(int j = 0; j < balances[0].length; j++)
balances[0][j] = 10000;
for(int i = 1; i < balances.length; i++){
for(int j = 0; j < balances[i].length; j++){
double oldBalance = balances[i-1][j];
double interest = ...;
balances[i][j] = oldBalance + interest;
}
}
注释: 二维数组使用 for each 循环时需要两个嵌套的循环,如下所示:
for(double[] row : a) for(double[] value : row) do somthing with value
不规则数组
Java 实际上并没有多维数组,只有一维数组。多维数组被解释为 ”数组的数组。“
我们来构造一个”不规则“数组。例如,下列代码:
final int NMAX = 10;
int[][] odds = new int[NMAX][];
for(int n = 0; n < NMAX; n++)
odds[n] = new int[...];
不行了,必须得睡觉了