好好学Java:从零基础到项目实战
上QQ阅读APP看书,第一时间看更新

3.3.1 一维数组

之前介绍的各类变量都是单独声明的,倘若要求定义相同类型的一组变量,则需定义许多同类型的变量,显然耗时耗力且不易维护。为此,编程语言引入了数组的概念,每个数组都由一组相同类型的数据构成,对外有统一的数组名称,对内通过序号区分每个数组元素。

数组类型由基本的变量类型扩展而来,在基本类型后面加上一对方括号便形成了该类型对应的数组类别。Java代码声明数组变量有两种形式:一种是在变量名称后面添加方括号,例如“int numbers[]”;另一种是在类型后面添加方括号,例如“int[] numbers”。两种形式表达的含义完全一致,都是声明一个名叫numbers的整型数组,只是书写习惯上有所区别。

声明完数组变量,还得给它分配存储空间。一个数组有多长,包含几个元素,这需要程序员事先予以指定。分配数组空间的途径有3种,分别说明如下:

(1)利用语句“new变量类型[数组长度]”分配空间,比如希望数组numbers能够容纳4个元素,则可通过下面这行语句实现:

        // 在方括号内填入数字,表示数组有多大
        numbers=new int[4];

其中,关键字new的意思是创建一块存储空间,方括号内的数字表示该数组的元素个数。

(2)在分配存储空间的时候立即对数组初始化赋值,此时方括号中间不填数字,而在方括号后面添加花括号,并且花括号内部是以逗号分隔的一组数值。此时初始化赋值的代码如下:

        // 方括号内留空,然后紧跟花括号,花括号内部是以逗号分隔的一组数值
        numbers=new int[]{2, 3, 5, 7};

(3)上面的第二种写法,之所以方括号内没填数字,是因为花括号里已经确定了具体的元素数量。既然程序能够自动推导元素的数量,那么从元素值也能推导该元素的变量类型。如此一来,花括号前面的“new int[]”完全是冗余的,于是就形成了以下的简化写法:

        // 以下是分配数组空间的第3种形式:赋值等号右边直接跟着花括号
        numbers={2, 3, 5, 7};

以上的赋值等号右边直接跟着花括号,花括号里面有4个整型数字,这便告诉编译器:该数组需要分配4个元素,并且每个元素都是整型数值。

现在数组变量总算占据一块地盘,根据数组名称加上元素序号即可访问对应位置的数组元素。获取某个数组元素的格式形如“数组名称[元素序号]”,譬如numbers[0]表示获取下标为0的数组元素,Java代码里的下标0对应日常生活中的第一个,因此numbers[0]指的就是第一个数组元素。这个数组元素的用法跟普通变量一样,既能对它赋值,又能把它打印出来。若要打印数组内部的所有元素数值,则可通过循环语句实现,通过“数组名称.length”获取该数组的长度,然后依次打印长度范围之内的所有元素。下面是声明一个整型数组,并对每个数组元素赋值,最后遍历打印各元素的完整代码例子(完整代码见本章源码的src\com\control\array\OneDimensional.java):

        // 以下是声明数组的第一种形式:“变量类型 数组名称[]”
        int numbers[];
        // 以下是分配数组空间的第一种形式:在方括号内填入数字,表示数组有多大
        numbers=new int[4];
        // 数组名称后面的“[数字]”就是数组元素的下标,表示当前操作的是第几个数组元素
        numbers[0]=2;  // 给下标为0的数组元素赋值,下标0对应日常生活中的第一个
        numbers[1]=3;  // 给下标为1的数组元素赋值,下标1对应日常生活中的第二个
        numbers[2]=5;  // 给下标为2的数组元素赋值,下标2对应日常生活中的第三个
        numbers[3]=7;  // 给下标为3的数组元素赋值,下标3对应日常生活中的第四个
        // 通过循环语句依次读出数组中的所有元素,“数组名称.length”表示获取该数组的长度
        for (int i=0; i<numbers.length; i++) {
            System.out.println("number="+numbers[i]);  // 打印下标为i的数组元素
        }

数组的一个应用方向为数学上的数列运算,比如常见的斐波那契数列。话说数学家斐波那契养了一对兔子,他发现兔子出生两个月后就有繁殖能力,并且一对兔子每个月能生产一对小兔子,那么一年过后,总共有多少对兔子?这个兔子问题看起来得一个月一个月去数,第一个月只有一对小兔子;第二个月小兔子长成大兔子,但总共仍是一对兔子;第三个月大兔子生下一对小兔子,加起来有两对兔子;第四个月大兔子又生下一对新的小兔子,上个月的小兔子长成大兔子,这下共有三对兔子……这么一路数到第十二个月,每个月的兔子数量情况整理如表3-3所示。

表3-3 兔子繁衍而来的斐波那契数列

表3-3所示的每月兔子的对数就构成了斐波那契数列,它的前12个数字依次为:1、1、2、3、5、8、13、21、34、55、89、144。仔细观察发现该数列有一个规律,从第3个数字开始,每个数字都是前两个数字之和,如3=2+1、5=3+2、8=5+3等。于是大可不必绞尽脑汁计算每个月的兔子生育情况,完全可以把这项工作交给计算机程序,让Java代码帮助我们求解斐波那契数列。为此先声明一个大小为12的整型数组,接着循环遍历该数组,依次填入每个元素的数值。按照上述思路编写的程序代码示例如下(完整代码见本章源码的src\com\control\Feibonaqi.java):

        int[] rabbitNumbers;  // 声明一个兔子数量(多少对)的数组变量
        rabbitNumbers=new int[12];  // 一年有12个月,故兔子数组大小为12
        // 用循环计算兔子数组在每个月的兔子对数
        for (int i=0; i<rabbitNumbers.length; i++) {
            if (i < 2) {  // 数列的头两个元素都是1
                rabbitNumbers[i]=1;
            } else {  // 从第3个元素开始,每个元素都等于它的前面两个元素之和
                rabbitNumbers[i]=rabbitNumbers[i-2] + rabbitNumbers[i-1];
            }
            int month=i+1;
            // 打印当前的月份和兔子对数
            System.out.println("第"+month+"个月,兔子对数="+rabbitNumbers[i]);
        }

最后运行上述的运算代码,得到以下日志记录,从中可见斐波那契数列的前12个数字。

第1个月,兔子对数=1

第2个月,兔子对数=1

第3个月,兔子对数=2

第4个月,兔子对数=3

第5个月,兔子对数=5

第6个月,兔子对数=8

第7个月,兔子对数=13

第8个月,兔子对数=21

第9个月,兔子对数=34

第10个月,兔子对数=55

第11个月,兔子对数=89

第12个月,兔子对数=144