第7章 特殊的引用数据类型——数组与方法

◎ 本章教学微视频:15个 75分钟

学习指引

在Java语言中,数组也是最常用的类型之一,它是引用类型的变量,数组是有序数据的集合,数组中的每一个元素都属于同一个数据类型。本章将详细介绍数组的使用,主要内容包括一维数组、二维数组、数组排序等。

重点导读

  • 了解数组的相关概念。
  • 掌握一维数组的使用方法。
  • 掌握数组排序的方法。
  • 掌握多维数组的使用方法。
  • 掌握对象数组的使用方法。
  • 掌握数组在方法中的使用。

7.1 数组的概念

数组,顾名思义就是一组数据。数组对于每一门编程语言来说都是重要的数据结构之一,当然不同语言对数组的实现及处理也不尽相同。Java语言中提供的数组用来存储固定大小的同类型元素。

如果需要存储大量的数据,例如需要读取100个数,那么就需要定义100个变量,显然重复写100次代码是没有太大意义的。为了解决这个问题,可以声明一个数组变量,如numbers[100]来代替直接声明100个独立变量number0,number1,…,number99。

在Java中,数组也可以认为是一种数据类型,它本身是一种引用类型。Java的数组可以存储基本类型的数据,也可以存储引用类型的数据。下面就是一个int类型数组的例子:

     int[] x;
     x = new int[100];

首先声明一个int[]类型的变量x,然后创建一个长度为100的数组。数组在创建过程中内存的分配情况如图7-1和图7-2所示。

图7-1 第一步:int[] x;

图7-2 第二步:x=new int[100];

7.2 一维数组

一维数组就是一组具有相同类型的数据的集合,一维数组中的元素是按顺序存放的。本节详细介绍如何声明和使用一维数组。

7.2.1 数组的声明

要使用Java中的数组,必须先声明数组,再为数组分配内存空间。一维数组的声明有两种方式,一般语法格式如下:

     数据类型 数组名[];
     数据类型[] 数组名;
  • 数据类型:指明数组中元素的类型。它可以是Java中的基本数据类型,也可以是引用类型。
  • 数组名:一个合法的Java标识符。
  • 中括号“[]”:表示数组的维数。一对中括号表示一维数组。

这两种声明的方法不同点在于[]的位置,Java建议使用的方法是将[]放在数据类型后面,而不是数组名后面。将[]放在数组名后面这种风格来自C/C++语言,在Java中也允许这种风格,其目的是让C/C++程序员能够快速理解Java语言。

Java语言使用new操作符来创建数组,语法格式如下:

     arrayRefVar = new dataType[arraySize];

上面的语句做了两件事:第一件事是使用dataType[arraySize]创建了一个数组,第二件事是把新创建的数组的引用赋值给变量arrayRefVar。

声明数组变量和创建数组可以用一条语句完成,具体语法格式如下:

     dataType[] arrayRefVar = new dataType[arraySize];

另外,用户还可以使用如下的方式创建数组。具体语法格式如下:

     dataType[] arrayRefVar = {value0, value1, …, valuek};

数组的元素是通过索引访问的。数组索引从0开始,所以索引值为0到arrayRefVar.length-1。

下面是这两种语法的具体应用实例。

【例7-1】(实例文件:ch07\Chap7.1.txt)声明数组应用实例。

     public class Test {
        public static void main(String[] args) {
            int[] ar1;                                          //声明变量
            ar1 = new int[3];                                   //创建数组对象
            System.out.println("ar1[0]=" + ar1[0]);             //访问数组中的第一个元素
            System.out.println("ar1[1]=" + ar1[1]);             //访问数组中的第二个元素
            System.out.println("ar1[2]=" + ar1[2]);             //访问数组中的第三个元素
            System.out.println("数组的长度是:" + ar1.length);  //打印数组长度
        }
     }

程序运行结果如图7-3所示。

图7-3 声明数组应用实例

本例中,首先声明了一个int[]类型的变量ar1,并将数组在内存中的地址赋给它。ar1[0]、ar1[1]、ar1[2]表示使用数组的索引来访问数组的元素,数组的索引从0开始,但元素没有赋值,所以显示的都是默认值0。数组对象有一个属性length,可以用来获得数组的元素个数,称为数组长度。

【例7-2】(实例文件:ch07\Chap7.2.txt)数组的声明,默认值和赋值应用实例。

     public class Test {
         public static void main(String[] args) {
             int[] arr = new int[4];  //定义可以存储4个整数的数组
             arr[0] = 1;                  //为第一个元素赋值1
             arr[2] = 3;                  //为第二个元素赋值2
             //下面的代码是打印数组中每个元素的值
             System.out.println("arr[0]=" + arr[0]);
             System.out.println("arr[1]=" + arr[1]);
             System.out.println("arr[2]=" + arr[2]);
             System.out.println("arr[3]=" + arr[3]);
         }
     }

程序运行结果如图7-4所示。

图7-4 数组的默认值和赋值

本例中,首先声明int[]类型的数组变量arr,长度为4。然后通过数组的索引进行赋值,但并没有对4个元素全部赋值,而是对arr[0]和arr[2]进行了赋值,所以结果显示它们的值分别为1和3,而arr[1]和arr[3]没有赋值,因此显示的是默认值0。

7.2.2 初始化数组

在Java中,初始化数组有动态和静态两种方式,下面分别进行介绍。在定义数组时,指定数组的长度,并由系统自动为元素赋初值,这些称为动态初始化。

【例7-3】(实例文件:ch07\Chap7.3.txt)数组动态初始化应用实例。

     public class Test {
         public static void main(String[] args) {
             int size = 10;                           //数组大小
             int[] myList = new int[size];            //定义数组
             myList[0] = 5;
             myList[1] = 4;
             myList[2] = 3;
             myList[3] = 2;
             myList[4] = 18;
             myList[5] = 25;
             myList[6] = 34;
             myList[7] = 68;
             myList[8] = 102;
             myList[9] = 1000;
             //计算所有元素的总和
             int total = 0;
             for (int i = 0; i < size; i++) {
                 total += myList[i];
             }
             System.out.println("总和为:" + total);
         }
     }

程序运行结果如图7-5所示。

图7-5 数组动态初始化

本例中,首先声明了一个数组变量myList,接着创建了一个包含10个int类型元素的数组,并且把它的引用赋值给myList变量,最后通过for语句计算出所有元素的和为1261。

数组的初始化还有一种静态方式,就是在定义数组的同时就为数组的每个元素赋值。数组的静态初始化有两种方式,具体格式如下:

     1. 类型[] 数组名 = new 类型[]{元素,元素,…};
     2. 类型[] 数组名 = {元素,元素,…};

这两种方式都可以实现数组的静态初始化,但第二种更简便,不易出错,因此建议使用第二种方式。

【例7-4】(实例文件:ch07\Chap7.4.txt)数组静态初始化应用实例。

     public class Test {
         public static void main(String[] args) {
             int[] ar1 = { 1, 2, 3, 4 }; //静态初始化
             String[] ar2 = new String[] { "Java", "PHP", "Python" };
             //下面的代码是依次访问数组中的元素
             System.out.println("ar1[0] = " + ar1[0]);
             System.out.println("ar1[1] = " + ar1[1]);
             System.out.println("ar1[2] = " + ar1[2]);
           System.out.println("ar1[3] = " + ar1[3]);
           System.out.println("ar2[0] = " + ar2[0]);
           System.out.println("ar2[1] = " + ar2[1]);
           System.out.println("ar2[2] = " + ar2[2]);
        }
     }

程序运行结果如图7-6所示。

图7-6 数组静态初始化

在本例中,使用两种静态初始化的方式为每个元素赋初值。int[]类型的数组没有采用new关键字,而是直接使用了{}来初始化元素的值。String[]类型的数组使用new String[]{}来初始化,这里要特别注意的是不能写成new String[3]{},这样编译器会报错。

7.2.3 数组的访问

数组实际上是一种简单的数据结构,它在计算机中是顺序存储的,要使用数组,实际上是要使用数组中的元素。例如有一个数组int[] a ={10, 8, 6, 20};,如下所示:

那么,如何找到并使用6这个数字呢?

数组的元素可以使用数组的索引来查找,索引又称为下标。数组的索引可以这样理解:对数组中的元素进行编号,可以把数组中的元素看成是正在排队,Java中数组索引是从0开始的,可以使用a.length获得数组a的元素个数。

用数组的索引访问数组元素。还是上面那个例子,如果要访问元素8,它的索引是1,那么就是a[1]。如果使用for循环,就可以把数组中的元素一一找出来并做处理。

【例7-5】(实例文件:ch07\Chap7.5.txt)访问数组元素应用实例。

     public class Test {
         public static void main(String[] args) {
             double[] myList = { 1.9, 2.9, 3.4, 3.5 };
             //打印所有数组元素
             for (int i = 0; i < myList.length; i++) {
                 System.out.println(myList[i] + " ");
             }
         }
     }

程序运行结果如图7-7所示。

图7-7 访问数组元素

在本例中,使用for循环遍历了数组的所有元素,读者一定要掌握这种写法。另外,Java JDK 1.5引进了一种新的循环类型,被称为for-each循环或者加强型循环,它能在不使用索引的情况下遍历数组。for-each循环的格式如下:

     for(type element: array)
     {
         System.out.println(element);
     }

【例7-6】(实例文件:ch07\Chap7.6.txt)使用for-each循环遍历数组元素应用实例。

     public class Test {
         public static void main(String[] args) {
             double[] myList = { 1.9, 2.9, 3.4, 3.5 };
             //打印所有数组元素
             for (double e : myList) {
                 System.out.println(e);
             }
         }
     }

程序运行结果如图7-8所示。

图7-8 使用for-each循环遍历数组元素

在本实例中,使用for-each循环对数组进行了遍历,for-each循环相对于for语句更简洁,但也有缺点,就是丢掉了索引信息。因此,当遍历数组时,如果需要访问数组的索引,那么最好使用for语句的方式来实现循环或遍历,而不要使用for-each循环。

7.3 数组的排序

数组排序的方法有很多种,主要有冒泡排序、选择排序、快速排序、插入排序、希尔排序等。本节通过例子详细介绍使用冒泡排序和选择排序对数组中元素进行排序的方法。

7.3.1 冒泡排序

冒泡排序(bubble sort),是计算机科学领域最常用的排序算法之一。冒泡排序就是比较相邻的两个数据,小的放在前面,大的放在后面,这样一趟下来,最小的数就被排在了第一位,第二趟也是如此,以此类推,直到所有的数据排序完成。这样数组元素中值小的就像气泡一样从底部上升到顶部。

【例7-7】(实例文件:ch07\Chap7.7.txt)一维数组元素使用冒泡排序方法。

程序运行结果如图7-9所示。

图7-9 冒泡排序

在本例中,声明并初始化了一个一维数组,通过for循环输出原数组的元素,然后通过冒泡排序对一维数组进行排序。

提示:使用冒泡排序时,首先比较数组中前两个元素,即array[i]和array[j],借助中间变量temp,将值小的元素放到数组的前面,即array[i]中,值大的元素在数组的后面,即array[j]中,最后将排序后的数组输出。

7.3.2 选择排序

选择排序(selection sort)是一种简单直观的排序算法。它的工作原理是:每一次从待排序的数组元素中选出最小(或最大)的一个元素,存放在序列的起始位置,直到全部待排序的数组元素排完。选择排序是不稳定的排序方法。所谓不稳定是指:如果一个数组中有值相同的多个元素,则排序后,这几个值相同的元素之间的先后顺序可能发生变化。

【例7-8】(实例文件:ch07\Chap7.8.txt)一维数组元素使用选择排序方法。

     public class ArraySelect {
         public static void main(String[] args) {
             int array[] = {15,6,2,13,8,4,};  //定义并声明数组
             int temp = 0;
             //输出未排序的数组
             System.out.println("未排序的数组:");
             for(int i=0;i<array.length;i++){
                 System.out.print(array[i] + " ");
             }
             System.out.println();                   //输出空行
             //选择排序
             for(int i=0;i<array.length;i++){
                 int index = i;
                 for(int j=i+1;j<array.length;j++){
                     if(array[index]>array[j]){
                         index = j;                  //将数组中值最小的元素的索引找出,放到index中
                     }
                 }
                 if(index != i){                     //如果值最小的元素不是索引为i的元素,将两者交换
                     temp = array[i];
                     array[i] = array[index];
                     array[index] = temp;
                 }
             }                                       //输出排好序的数组
             System.out.println("选择排序,排好序的数组:");
             for(int i=0;i<array.length;i++){
                 System.out.print(array[i] + " ");
             }
         }
     }

程序运行结果如图7-10所示。

在本例中,声明并初始化了一个一维数组,通过for循环输出数组的值。通过选择排序算法,对一维数组进行排序。

图7-10 选择排序

7.4 多维数组

多维数组的声明与一维、二维数组类似,一维数组要使用一个大括号,二维数组要使用两个大括号,以此类推。三维数组或更高维的数组并不常用,经常使用的多维数组是二维数组,本节主要介绍二维数组的使用。

7.4.1 数组的声明

多维数组可以看成数组的数组。二维数组就是一个特殊的一维数组,其每一个元素都是一个一维数组,例如:

     String str[][] = new String[3][4];

多维数组的动态初始化(以二维数组为例)有两种方式,下面分别进行介绍。

(1)直接为每一维分配空间,格式如下:

     type arrayName = new type[arraylength1][arraylength2];

type可以为基本数据类型和复合数据类型,arraylength1和arraylength2必须为正整数,arraylength1为行数,arraylength2为列数。

例如:

     int a[][] = new int[2][3];

解析:二维数组a可以看成一个两行三列的数组。

(2)从最高维开始,分别为每一维分配空间,例如:

     String s[][] = new String[2][];
     s[0] = new String[2];
     s[1] = new String[3];
     s[0][0] = new String("Good");
     s[0][1] = new String("Luck");
     s[1][0] = new String("to");
     s[1][1] = new String("you");
     s[1][2] = new String("!");

解析:s[0]=new String[2];和s[1]=new String[3];是为最高维分配引用空间,也就是为最高维限制其能保存数据的最大长度,然后再为每个数组元素单独分配空间,即s[0][0]=new String("Good");等操作。

7.4.2 数组的内存分配

声明二维数组后,要为二维数组分配内存空间,才可以使用。为二维数组分配内存空间的语法格式如下:

     数据类型[][] 数组名 = new 数据类型[第一维数][第二维数];
  • 数组名:一个合法的标识符。
  • new:为数组分配内存空间的关键字。
  • 第一维数:指二维数组中一维数组个数,相当于行数。
  • 第二维数:指一维数组内元素的个数,相当于列数。

注意:在为二维数组分配内存时,也可以对它的每个一维数组单独分配内存空间,并且分配的内存长度可以不同。在第一个中括号中定义一维数组的个数,然后利用一维数组分配内存的方式分配内存。

【例7-9】(实例文件:ch07\Chap7.9.txt)为二维数组分配内存,指定二维数组的维数。

     int array = new int[3][5];  //为声明的二维数组分配内存

在本例中,定义二维数组时指定了二维数组的维数,是一个3行5列的规则的数组。

【例7-10】(实例文件:ch07\Chap7.10.txt)为二维数组分配内存,只指定二维数组第一维的维数。

     int array[][] = new int[3][];  //二维数组分配内存,指定了二维数组第一维的维数是3
     array[0] = new int[3];               //确定二维数组第二维的维数是3
     array[1] = new int[2];               //确定二维数组第二维的维数是2
     array[2] = new int[4];               //确定二维数组第二维的维数是4

在本例中,声明二维数组时只指定二维数组第一维的维数,即指定一维数组个数为3。没有指定二维数组第二维的维数,即没有指定一维数组元素的个数,而是利用一维数组的内存分配的方式单独为它们分配内存。在本例中,对二维数组第二维分配的维数不同,即3个一维数组array[0]、array[1]和array[2]的长度不等,这是一个不规则的二维数组。

7.4.3 数组的元素

二维数组也是通过数组的索引来访问数组中的元素。一般格式如下:

     数组名[第一维索引][第二维索引]
  • 数组名:数组的名称。
  • 索引:范围是0到数组元素个数-1。

二维数组的长度表示格式如下:

     二维数组名.length

【例7-11】(实例文件:ch07\Chap7.11.txt)二维数组索引的使用。

     int array[][] = new int[3][2];  //定义规则的二维数组
     array[0][0] = 1;                //表示数组中第0行第0列的元素
     array[0][1] = 2;                //表示数组中第0行第1列的元素
     array[1][0] = 3;                //表示数组中第1行第0列的元素
     array[1][1] = 4;                //表示数组中第1行第1列的元素
     array[2][0] = 5;                //表示数组中第2行第0列的元素
     array[2][1] = 6;                //表示数组中第2行第1列的元素

在本例中,二维数组的内存结构如图7-11所示。

图7-11 二维数组的内存结构

7.4.4 数组的赋值

声明二维数组时,也可以直接对数组赋值,将赋给数组的值放在大括号中,多个数值之间使用逗号(,)隔开。声明并初始化数组的一般格式如下(这里假设第二维长度为3):

     数据类型 数组名[][] = {{初值1,初值2,初值3},{初值4,初值5,初值6},…};

【例7-12】(实例文件:ch07\Chap7.12.txt)声明二维数组并初始化。

     int array[] [] = {{1,2,3},{4,5},{6,7}};     //声明并初始化一个不规则二维数组
     int array[][] = {{1,2,3},{4,5,6},{7,8,9}};  //声明并初始化规则数组

在声明二维数组时初始化,这时二维数组的维数可以不指定,系统会根据初始化的值来确定二维数组第一维的维数和第二维的维数。

注意:初始化数组时,要明确数组的索引是从0开始的。

7.4.5 遍历多维数组

本节以二维数组为例来介绍对多维数组的遍历。遍历二维数组中的每个元素的格式如下:

     arrayName[index1][index2],

例如:

     num[1][0];

【例7-13】(实例文件:ch07\Chap7.13.txt)使用for循环遍历二维数组。

程序运行结果如图7-12所示。

图7-12 for循环遍历数组

在本例中,创建了一个3行3列的二维数组num,并为每个元素赋值,通过for循环将数组的所有元素显示出来。

【例7-14】(实例文件:ch07\Chap7.14.txt)使用for-each循环遍历二维数组。

程序运行结果如图7-13所示。

图7-13 for-each循环遍历数组

在本例中,创建了一个3行3列的二维数组num,并为每个元素赋值,通过for-each循环将数组的所有元素显示出来。

7.5 对象数组

Java API提供了一个数组类Arrays(java.util.Arrays),能方便地操作数组,它提供的所有方法都是静态的,具有以下功能:

  • 给数组赋值:通过fill方法实现。
  • 对数组排序:通过sort方法实现,按升序。
  • 比较数组:通过equals方法比较数组中的元素值是否相等。
  • 搜索数组元素:通过binarySearch(二分搜索)方法能对排好序的数组进行搜索操作。

具体方法的应用及说明如表7-1所示。

表7-1 对象数组的功能方法及说明

7.5.1 静态sort()方法

使用sort()方法可以对指定对象数组根据其元素的自然顺序按升序排列。

【例7-15】(实例文件:ch07\Chap7.15.txt)数组倒序。

程序运行结果如图7-14所示。

图7-14 数组倒序

【例7-16】(实例文件:ch07\Chap7.16.txt)数组排序。

程序运行结果如图7-15所示。

图7-15 数组排序

在本例中,使用数组类Arrays的静态方法sort()对数组的元素按升序排列,然后使用for循环将数组元素安排列后的顺序显示出来。

7.5.2 binarySearch()方法

Arrays类还有一个常用的方法——binarySearch(),可以使用二分搜索法来搜索指定的数组,以获得指定对象。该方法返回要搜索元素的索引值。binarySearch()方法提供多种重载形式,用于满足各种类型数组的搜索需要。

需要注意的是,使用binarySearch()方法前,必须先用Arrays.sort()方法排序,否则结果可能不符合预期。binarySearch()有两种参数形式,下面分别介绍。

1.binarySearch(Object[] a, Object key)

其中参数a表示要搜索的数组,参数key表示要搜索的值。如果key在数组中,则返回搜索值的索引;否则返回-1或“-”后跟插入点的索引。插入点是索引键将要插入数组的那一点,即第一个大于该键的元素的索引。使用这个方法有一些技巧需要注意:

  • 搜索值不是数组元素,且在数组元素值范围内,从1开始计数,返回“-”后跟插入点索引。
  • 搜索值是数组元素,从0开始计数,返回搜索值的索引。
  • 搜索值不是数组元素,且大于数组内的所有元素,索引为-(length +1)。
  • 搜索值不是数组元素,且小于数组内的所有元素,索引为-1。

下面看一个例子。

【例7-17】(实例文件:ch07\Chap7.17.txt)binarySearch()方法实例一。

程序运行结果如图7-16所示。

图7-16 binarySearch()方法实例一

在本例中,首先定义数组arr有6个元素,为{4, 3, 1, 9, 5, 8},经过排序后顺序是{1, 3, 4, 5, 8, 9}。下面分析s1、s2、s3和s4的结果。

  • s1是要在数组arr中查找6,结果是-5,-表示没有查询结果,说明数组arr中没有元素6,5又在元素索引范围内,说明要查找的6没有超过数组的最大元素,在数组元素值范围内。根据规定,从1开始计数,5表示6在数组arr的第4个元素后面。
  • s2是要在数组arr中查找4,结果是2,表示有查询结果,根据规定,从0开始计数,2表示索引,也就是4在数组arr的第2个元素后面。
  • s3是要在数组arr中查找10,结果是-7,-表示没有查询结果,说明数组arr中没有元素10,7已经超过了元素索引范围,说明要查找的10超过了数组的最大元素,不在数组元素值范围内。根据规定,从1开始计数,7表示length+1,数组arr的length为6,表示10在数组arr的最后一个元素后面。
  • s4是要在数组arr中查找0,结果是-1,-表示没有查询结果,说明数组arr中没有元素0,1表示0小于数组内元素,说明0在数组arr的第一个元素之前。

2.binarySearch(object[] a, int fromIndex, int endIndex, object key)

其中参数a表示要搜索的数组,fromIndex表示指定范围的开始处索引(包含),toIndex表示指定范围的结束处索引(不包含),参数key表示要搜索的值。如果要搜索的元素key在指定的范围内,则返回搜索值的索引;否则返回-1或“-”后跟插入点索引。使用这个方法有一些技巧需要注意:

  • 该搜索键在指定范围内,但不是数组元素,由1开始计数,返回“-”后跟插入点索引。
  • 该搜索键在指定范围内,且是数组元素,由0开始计数,返回搜索值的索引。
  • 该搜索键不在指定范围内,且小于指定范围(数组)内元素,返回-(fromIndex+1)。
  • 该搜索键不在指定范围内,且大于指定范围(数组)内元素,返回-(toIndex+1)。

下面看一个例子:

【例7-18】(实例文件:ch07\Chap7.18.txt)binarySearch()方法实例二。

程序运行结果如图7-17所示。

图7-17 binarySearch()方法实例二

在本例中,首先定义数组arr有6个元素,为{1, 3, 4, 5, 8, 9},经过排序后顺序不变。下面分析s1、s2、s3和s4的结果。

  • s1是要在数组arr的索引1至索引3中查找6,也就是从数组arr的元素3、4、5中查找6,结果是-4,-表示没有查询结果,说明指定范围中没有元素6,4不在元素索引范围1至3内,说明要查找的6超过了3、4、5的最大元素,根据规定,4表示toIndex + 1,toIndex是3,6在数组arr的元素5后面。
  • s2是要在数组arr的索引1至索引3中查找4,也就是从数组arr的元素3、4、5中查找4,结果是2,表示4在数组arr的索引2位置。
  • s3是要在数组arr的索引1至索引3中查找2,也就是从数组arr的元素3、4、5中查找2,结果是-2,-表示没有查询结果,说明指定范围中没有元素2,根据规定,2表示fromIndex + 1,fromIndex是1,2在数组arr的元素3前面。
  • s4是要在数组arr的索引1至索引3中查找10,也就是从数组arr的元素3、4、5中查找10,结果是-4,-表示没有查询结果,说明指定范围中没有元素10,4不在元素索引范围1至3内,说明要查找的10超过了3、4、5的最大元素,根据规定,4表示toIndex + 1,toIndex是3,10在数组arr的元素5后面。
  • s5是要在数组arr的索引1至索引3中查找0,也就是从数组arr的元素3、4、5中查找0,结果是-2,-表示没有查询结果,说明指定范围中没有元素0,根据规定,2表示fromIndex + 1,fromIndex是1,0在数组arr的元素3前面。

7.6 数组在方法中的使用

在Java语言中,方法可以有多个参数,参数之间使用逗号(,)隔开。方法的参数(形参)若是简单数据类型,方法调用时直接接收实参的值,但不改变实参的值,这是值传递;方法的参数(形参)若是引用数据类型,方法调用时接收的是引用,可以改变实参的值,这是引用传递。数组作为方法中的参数就是一种引用的传递。下面通过一个例子介绍数组作为方法的参数的使用。

【例7-19】(实例文件:ch07\Chap7.19.txt)编写Java程序,在程序中定义一维数组array[],将数组作为方法的参数,在方法中修改数组元素,最后在程序中输出数组元素。

     public class ArrayMethod {
         public static void change(char[] c,int length){
             for(int i=0;i<length;i++){
                 if(c[i]=='l'){  //修改形参数组元素
                     c[i] = 'w';  //将形参数组中所有字符l修改为w
                     //System.out.println("ok");
                 }
             }
         }
         public static void main(String[] args) {
             char array[] = {'h','e','l','l','o','j','a','v','a'};
             //使用for循环,输出原数组元素
             System.out.println("调用方法前,数组元素:");
             for(int i=0;i<array.length;i++){
               System.out.print(array[i] + " ");
           }
           System.out.println();
           //调用方法改变数组中的元素
           change(array,array.length);
           //使用for循环,输出更改后的数组元素
           System.out.println("调用方法后,数组元素:");
           for(int i=0;i<array.length;i++){
               System.out.print(array[i] + " ");
           }
        }
     }

程序运行结果如图7-18所示。

图7-18 数组作为形参

数组的内存分析如图7-19所示。

图7-19 形参和实参

在本例中,定义了一个方法change(),将一维数组array[]、数组的长度作为方法的参数,在方法中将数组元素l修改为w。在main()方法中,通过for循环输出原数组元素和修改后的数组元素,可以看到在方法中对形参数组的操作,使得实参数组发生了改变,这就是引用传递的效果。形参数组c[]和实参数组array[]指向同一对象。

7.7 就业面试解析与技巧

7.7.1 面试解析与技巧(一)

面试官:Java变量一定要初始化吗?

应聘者:不一定。Java数组变量是引用数据类型变量,它并不是数组对象本身,只要让数组变量指向有效的数组对象,即可使用该数组变量。对数组执行初始化,并不是对数组变量进行初始化,而是对数组对象进行初始化,也就是为该数组对象分配一块连续的内存空间,这块连续的内存空间就是数组的长度。

7.7.2 面试解析与技巧(二)

面试官:数组作为方法的形参,在方法中修改形参数组的值,为什么实参数组的值也被修改了?

应聘者:在方法中数组作为参数传递的只是数组在内存中的地址(即引用),而不是将数组中的元素直接传给形参。这样的引用传递使方法的形参和实参同时指向数组在内存中的位置,无论是通过形参还是实参修改数组,内存中数组的值都会发生改变。