第3 章 数 组 数组是由类型相同的元素顺序组成的一个集合,每个数组都有一个唯一的名称,即数组 名。通过数组名和下标可以方便地访问数组中的每个成员。本章主要讲述Java中一维和二 维数组的创建和使用方法。通过本章的学习,应该重点掌握以下主要内容: (1)一维数组的定义和产生方法。 (2)一维数组的初始化方法。 (3)一维数组的引用方法。 (4)二维数组的创建和引用方法。 3.1 数组使用初探 Java程序中通常使用变量来存放各种类型的数据,如将10个数分别存放在10个变量中, 但这会非常麻烦,因为需要的变量名实在太多了。这时就可以考虑用一个数组变量来存放它 们,并通过一个下标来访问存入数组中的每个成员。 【例3.1】 求10个学生某门课程的平均成绩。 分析:如果用变量s1,s2,…,s10来保存10个学生的成绩,显然不合适(变量太多且随 学生人数递增),而如果使用数组s来保存这些成绩,则问题可以处理如下: package code0301; public class AvgGrade { public static void main(String args[]) { int total = 0; int s[] = { 75, 69, 80, 85, 93, 97, 79, 77, 68, 90 }; //定义数组变量s 并赋值 double avg = 0; for (int i = 0; i < 10; i++) { total = total + s[i]; //访问数组成员s[i] } avg = total / 10.0; //求平均分avg System.out.println("The average score is :" + avg); } } 程序运行结果: 数组 第3章 4 1 The average score is :81.3 该问题的求解涉及两个关键点: (1)定义数组变量s,将所有值{75,69,80,85,93,97,79,77,68,90}存入其中。 (2)通过数组变量s加下标i的形式访问数组中每个成员:total=total+s[i]。 3.2 一维数组 与简单变量一样,数组必须先定义后使用。定义数组时,除了要给定数组的名称、数组成 员类型,还要为其分配内存空间并进行初始化。 3.2.1 定义数组 一维数组的定义格式如下: 数据类型数组名[ ]; 其中,数据类型是指数组成员的类型,可以为基本数据类型,也可以为引用数据类型。[] 为数组标记。在定义数组时,不允许在[]内指定数组元素的个数。例如: int a[ ], boolean temp[ ], String s[ ]; 表示数组a的数据类型为int,temp的数据类型为boolean,s的数据类型为类String。 提示:定义数组时,另外一种可选形式为直接将方括号放在变量类型的后边。例如: int[ ] a, boolean[ ] temp, String[ ] s 3.2.2 生成数组 数组定义只是建立了一种数组的引用,还必须使用关键字new 为其分配内存空间,否则 它是无法被访问的。基本形式如下: 数组变量名= new 数据类型[数组长度] 例如: char s[]; s=new char[5]; 的作用是为数组s分配5×2B大小的空间。也可以在定义数组的同时为之分配内存空间, 例如: int temp[]=new int[10]; 3.2.3 初始化数组 当使用关键字new生成数组时,数组中的每个成员都会被自动初始化,初始值依据数组 的类型而定。例如: 数值型的初始值:0; 字符型的初始值:'\0'; 布尔型的初始值:false; 类对象的初始值:null; Java 程序设计(第3 版) 4 2 也可以通过主动赋值的方式对数组进行初始化。例如 int s[ ]=new int[3]; s[0]=1; s[1]=2; s[2]=3 还可以将数组的定义、内存空间分配、初始化工作放在一条语句中,格式如下: 数据类型数组名[ ]={值1,…,值n} 这种数组初始化形式的特点是无须给出数组的长度,系统会根据初始值的数量自动确定 数组的长度,并依次将每个数组成员放在数组中。例如: int s[ ]={1,2,3}; 使得数组长度为3,且s[0]=1;s[1]=2;s[2]=3。 数组不能整体赋值,例如,下列语句是错误的: char s[]=new char[5]; s[]={'a','b','c','d','e'}; //错误 提示:必须给出数组长度,而且数组一旦创建,就不允许再增加它的空间。 3.2.4 访问数组 数组成员的访问是通过数组名和下标来实现的,Java中的下标是从0开始的,依次递增 1,如果数组temp的长度为10,则数组下标为0~9。这些成员分别表示为 temp[0],temp[1],…,temp[9] 对数组中任意成员的引用形式为:数组名[下标]。 例如,temp[4]表示引用数组temp的第5个元素。数组元素的用法和平常使用的普通变 量没有什么差异,也可以被赋值或参与其类型允许的各种运算等。例如: int i=temp[0]%2; temp[1]=temp[0]*5; System.out.println("value="+temp[2]); 使用数组时要注意数组是否越界,每个数组一个属性length,可以通过数组名.length来 获取数组的长度,即数组元素的个数。 3.2.5 实用案例3.1:求一维数组的最大值及位置 为给一维数组进行随机赋值,本例采用Math.random()方法产生随机数。 【例3.2】 求一维数组的最大值及位置。 package Code0302; public class MaxNum { public static void main(String[] args) { final int ARRAY_SIZE = 10; int a[] = new int[ARRAY_SIZE]; int max = 0; int index = 0; //存储最大元素的位置 for (int i = 0; i < a.length; i++) { //本例中a.length=10 a[i] = (int) (Math.random() * 10); //产生随机数,并对数组成员赋值 System.out.print(" " + a[i]); } 数组 第3章 4 3 System.out.println(); max = a[0]; for (int j = 1; j < ARRAY_SIZE; j++) { if (a[j] > max) //判断当前位置的数是否大于最大值max { max = a[j]; index = j; //替换当前的最大值,记住对应位置 } } System.out.println("A[" + index + "] has maximum value " + a[index]); } } 程序可能的输出结果: 2 0 0 1 9 5 1 4 2 7 A[4] has maximum value 9 分析:第一个for循环依次将随机数读入下标为i的数组中,完成初始化操作;第二个 for循环依次取出每个数组元素a[j]的值,并判断其是否为当前最大值。 提示:如果例3.2中第二个for循环改为for(intj=1;j<=ARRAY_SIZE;j++),则 出现数组下标越界的情况,因为a[10]并不存在。 3.3 二维数组 到目前为止使用的都是一维数组,但有时应用中需要使用多维数组才能充分地存储数据。 例如,(x,y)坐标系统中,如果需要存储坐标x和坐标y来标识一个点,则需要使用二维数组, 其中一维用于存储坐标x,另一维用于存储坐标y。 将数组的下标数称为数组的维数,维数大于1的数组称为多维数组。因为多维数组的操 作比较相似,本节重点介绍二维数组。 3.3.1 定义二维数组 二维数组的定义与一维数组相似: 数据类型 数组名[ ][ ]; 两个方括号表示这是一个二维数组。当然,它也支持另一种形式: 数据类型[ ][ ] 数组名; 与一维数组相似,二维数组的创建可以先定义数组,再分配内存空间,也可以同时进行这 两项工作。例如: int temp[][]; temp=new int[2][3]; int temp[][]=new int[2][3]; 这样即创建了一张二维结构的数组,其中行数为2,列数为3。也可将其看作一个长度为 2的一维数组,每个数组成员又是一个长度为3的一维数组。这些数组成员按行排列为 Java 程序设计(第3 版) 4 4 temp[0][0], temp[0][1], temp[0][2] temp[1][0], temp[1][1], temp[1][2] 同样,可以在定义数组的同时对其进行初始化。例如: int temp[][]={{1,2},{3,4},{5,6}} 系统自动根据初始值的情况,为数组指定大小长度,并依次将值填入相应的单元中,例如初始 化后temp[0][1]=2,temp[2][0]=5。 注意:等式右边大括号内嵌套的大括号不能省略,它代表数组的一行及其组成。 3.3.2 二维数组元素的引用 引用二维数组元素的方式如下: 数组名[下标1][下标2] 下标仍然是从0开始逐渐递增的,同样在引用时要注意数组的越界问题。二维数组也有 length属性,可以求每一维数组的长度。例如: int temp[][]=new int[3][5]; System.out.println(temp.length); //求二维数组的长度实际是求它的行数3 System.out.println(temp[0].length); //每个数组成员又是一个一维数组,其长度为5 【例3.3】 求二维数组中各元素的和。 package code0303; public class SumAll{ public static void main(String args[]){ int total=0; int arr[][]=new int[3][4]; for(int i=0;i<arr.length;i++){ //初始化并显示二维数组 for(int j=0;j<arr[i].length;j++){ arr[i][j]=i+j; System.out.print(" " + arr[i][j]); } System.out.println(); } for(int i=0;i<arr.length;i++) //求和 for(int j=0;j<arr[i].length;j++){ total = total +arr[i][j]; } System.out.println(" The Sum is:"+total); } } 程序运行结果: 0 1 2 3 1 2 3 4 2 3 4 5 The Sum is:30 3.3.3 实用案例3.2:求两个矩阵的乘积 根据矩阵的乘法规则,两个矩阵相乘将产生一个新的矩阵,如a[4,3]×b[3,2]将产生一 数组 第3章 4 5 个r[4,2]的新矩阵,其中的某个元素r[i][j]=a[i][0]×b[0][j]+a[i][1]×b[1][j]+a[i] [2]×b[2][j]。例如: x= 1 6 3 8 . è . . . ÷ × 2 2 9 7 . è . . . ÷ 其计算过程为 1×2+6×9=56 1×2+6×7=44 3×2+8×9=78 3×2+8×7=62 因此结果为56 44 78 62 . è . . . ÷ 。 【例3.4】 求两个矩阵的乘积。 public class MatrixMultiply { public void multiply(int[][] a,int[][] b) { int [][] r = new int[4][2]; //r 用于存放运算结果 int tmp =0; for (int k =0; k < r[0].length; k++) { //双重循环,遍历a 矩阵 for (int i = 0; i< a.length; i++ ) { tmp = 0; for (int j = 0; j < a[0].length; j++) { tmp += a[i][j] * b[j][k] ; } r[i][k]=tmp; } } for (int i = 0; i < r.length; i++) { for (int j = 0; j < r[0].length; j++) { System.out.print(r[i][j] + "\t"); } System.out.println(); } } public static void main(String[] args) { int[][] a = new int[][] { { 1, 2, 3 }, { 4, 5, 6 }, { 7, 8, 9 }, { 11, 12, 13} }; int[][] b = new int[][]{ {1,2}, {3,4}, {5,6} } ; MatrixMultiply ma=new MatrixMultiply(); ma.multiply(a,b); } } Java 程序设计(第3 版) 4 6 3.4 Arrays类 为了更方便地操作数组,Java在包java.util定义一个叫Arrays的类,该类包含了如下几 个用static修饰的静态方法。 (1)statictype[]copyOf(type[]original,intlength):将original数组复制为一个新数 组,其中length为新数组的长度。 (2)staticintbinarySearch(type[]a,typekey):使用二分搜索法在类型为type的数组 中搜索类型为type的指定值key。 (3)staticbooleanequals(type[]a,type[]b):比较两个类型为type的数组是否相等。 (4)staticvoidfill(type[]a,typeval):用一个指定的值val填充类型为type的数组a。 (5)staticvoidfill(type[]a,intfromIndex,inttoIndex,typeval):与前一个方法类似, 但填充时仅仅针对下标为fromIndex到toIndex-1的数组元素赋值为val。 (6)staticvoidsort(type[]a):对类型为type的数组排序。 上述每个方法的具体描述,请参考JDK文档。 【例3.5】 Arrays类的基本使用。 package code0304; import java.util.Arrays; public class ArraysDemo { public static void main(String[] args) { Integer array[] = new Integer[9]; for (int i = 1; i < 10; i++) array[i - 1] = (int) (Math.random() * 100); //显示,排序数组 System.out.print("原内容: "); display(array); Arrays.sort(array); System.out.print("排序后: "); display(array); //将值-1 分配给数组array 中下标从0~3-1 位置上的元素 Arrays.fill(array, 0, 3, -1); System.out.print("执行fill()后: "); display(array); //搜索39 System.out.print("值39 的位置"); int index = Arrays.binarySearch(array, 39); System.out.println(index); } static void display(Integer array[]) { for (int i = 0; i < array.length; i++) System.out.print(array[i] + " "); System.out.println(""); } } 程序运行结果: 原内容: 90 48 81 14 3 35 95 4 97 排序后: 3 4 14 35 48 81 90 95 97 数组 第3章 4 7 执行fill()后: -1 -1 -1 35 48 81 90 95 97 值39 的位置-5 提示:Java8对Arrays类的功能进行了增强。如增加了一些新的方法,可以利用多 CPU 的并行处理能力提高数组排序、赋值等操作性能;parallelSort(type[]a)方法与之前介绍 的sort()方法相似,但可以在多CPU 上并行实现。 实用案例3.3 对数组按中文名称排序 【例3.6】 对数组按中文名称排序。 package code0304; import java.text.Collator; import java.util.Arrays; import java.util.Comparator; public class SortByChinese { public static void main(String[] args) { String[] arrStrings = {"计算机","长江", "通信","数学"}; Arrays.sort(arrStrings); for (int i = 0; i < arrStrings.length; i++) System.out.println(arrStrings[i]); System.out.println("----------------------------"); //Collator 类用来执行区分语言环境的字符串比较,这里选择用CHINA Comparator comparator = Collator.getInstance(java.util.Locale.CHINA); //根据指定比较器产生的顺序对指定对象数组进行排序 Arrays.sort(arrStrings, comparator); for (int i = 0; i < arrStrings.length; i++) System.out.println(arrStrings[i]); } } 程序运行结果: 数学 计算机 通信 长江 ---------------------------- 长江 计算机 数学 通信 Arrays类中的sort()方法缺省,那么按照数组中数值的大小或字母顺序进行排序,但这 种处理方式对中文是无效的,如上例运行结果。为此,我们使用了类Arrays中另一种形式的 sort()方法:sort(T[]a,Comparator<?superT>c),它可以根据指定比较器Comparator 产生的顺序对对象数组进行排序。为获取Comparator 对象,可以通过方法Collator. getInstance()实现,其中参数java.util.Locale.CHINA 表示按中文语言进行排序。 Java 程序设计(第3 版) 4 8 3.5 数组实训任务 【任务描述】 编写一个模拟的Java发牌程序,要求将2副牌(即108张牌)发给4个人,并留8张底牌, 最后输出底牌和每个人手中的牌。 【任务分析】 (1)首先确定扑克牌在计算机中的表达方式,因为计算机中无法表达扑克牌中的花色,因 此最好为每张牌设定一个编号,拟定的编号规则如下: 红桃按照从小到大依次为1~13。 方块按照从小到大依次为14~26。 黑桃按照从小到大依次为27~39。 梅花按照从小到大依次为40~52。 小王为53,大王为54。 (2)由于可发的牌和每个玩家手中的牌都需要记录,且其由多个有序数据组成,因此需要 设计两个数组,以存放108张牌和每个玩家手中的牌。 (3)整个程序由以下4部分构成: ① 按照以上编号规则初始化一个包含108个数字的数组。 ② 每次随机从该数组中抽取一个数字,分配给保存玩家数据的数组。 ③ 循环输出每个玩家手中的牌。 ④ 最后输出底牌。 【任务解决】 【例3.7】 模拟发牌。 package code0305; import java.util.*; public class CardPlay{ public static void main(String[] args){ int[] total = new int[108]; //存储108 张牌的数组 int[][] player = new int[4][25]; //存储4 个玩家的牌 int leftNum = 108; //当前剩余牌的数量 int ranNumber; Random random = new Random(); //生成Random 对象,用以生成随机数 for(int i = 0;i < total.length;i++){ //初始化一维数组 total[i] = (i + 1) % 54; if(total[i] == 0){ //处理大小王编号 total[i] = 54; } } //循环发牌 for(int i = 0;i < 25;i++){//为每个人发牌 for(int j = 0;j < player.length;j++){ /生成随机下标 ranNumber = random.nextInt(leftNum); //random.nextInt 方法生成随机数 player[j][i] = total[ranNumber]; / /发 牌 total[ranNumber] = total[leftNum - 1]; //删除已经发过的牌 leftNum--; 数组 第3章 4 9 } } //循环输出玩家手中的牌 for(int i = 0;i < player.length;i++){ //通过两层循环遍历二维数组 System.out.print("玩家" + i+ "的牌:"); for(int j = 0;j < player[i].length;j++){ System.out.print(" " + player[i][j]); } System.out.println(); } //底牌 System.out.print("底牌:"); for(int i = 0;i < 8;i++){ System.out.print(" " + total[i]); } System.out.println(); } } 程序运行结果: 玩家0 的牌: 52 15 12 53 32 24 48 36 24 11 54 27 14 22 3 8 10 40 43 46 40 45 37 41 22 玩家1 的牌: 49 25 5 47 20 35 45 51 29 17 10 26 20 51 3 1 29 43 31 9 33 30 32 4 53 玩家2 的牌: 42 7 13 38 34 50 12 6 39 49 33 23 14 31 7 19 39 48 16 18 35 5 41 9 11 玩家3 的牌: 44 2 30 26 28 46 44 19 21 23 25 21 15 13 1 28 34 52 4 8 6 47 17 2 27 底牌: 50 42 18 37 16 38 36 54 1.为了定义3个整型数组a1、a2、a3,下面声明正确的语句是哪一个? A.intArray[]a1,a2; inta3[]={1,2,3,4,5}; B.int[]a1,a2; inta3[]={1,2,3,4,5}; C.inta1,a2[]; inta3={1,2,3,4,5}; D.int[]a1,a2; inta3=(1,2,3,4,5); 2.编程实现两个同行列数矩阵的加法运算。 3.将给定数组inta[]={78,23,56,34,12,45,67,89}按从小到大顺序进行排序并输出。 4.给出下列程序段运行的结果: public static void main(String args[]) { int array[]={1,2,3,4,5}; printarray(array); could_modify(array); printarray(array); } Java 程序设计(第3 版) 5 0 static void could_modify(int a[]){ for(int i=0;i<a.length;i++) a[i]*=i; }s tatic void printarray(int a[]) { for(int i=0;i<a.length();i++) System.out.println(a[i]); } 5.数组创建后,可否通过设置变量length的大小来增减数组的大小?