一维数组(Java)

一维数组

Java 和许多高级语言都提供了一种称作数组(array)的数据结构,可以用它来存储一个元素个数固定元素类型相同的有序集。

一维数组、二维数组和多维数组。

一旦数组被创建,它的大小是固定的。使用一个数组引用变量,通过下标来访问数组中的元素。

数组是用来存储数据的集合。把数组看作一个存储具有相同类型的变量集合。单个的数组变量可以引用一个大的数据集合。

声明数组变量

为了在程序中使用数组,必须声明一个引用数组的变量,并指明数组的元索类型。
下面是声明数组变量的语法:

//元素类型[] 数组引用变量;
elementType[] arrayRefVar;

elementType可以是任意数据类型,但是数组中所有的元素都必须具有相同的数据类型。
arrayRefVar(即字面量指向了地址)。

也可以用 C/C++ 语言的风格声明数组变量:

//元素类型 数组引用变量[];
elementType arrayRefVar[];

推荐使用 elementType[] arrayRefVar(元素类型 []数组引用变量) 风格。

创建数组

不同于基本数据类型变量的声明,声明一个数组变量时并不在内存中给数组分配任何空间,只是创建一个对数组的引用的存储位置。如果变量不包含对数组的引用,那么这个变量的值为 null 。
声明数组变量之后,可以使用下面的语法用 new 操作符创建数组,并且将它的引用賦给一个变量:

//数组引用变量 =new 元素类型[数组大小];
arrayRefVar = new e1ementType[arraySize];
  1. 使用 new elementType[arraySize] 创建了一个数组;
  2. 把这个新创建的数组的引用陚值给变暈 arrayRefVar 。

声明一个数组变量、创建数组、将数组引用赋值给变量这三个步骤可以合并在一条语句里,如下所示:

//元素类型[] 数组引用变量 =new 元素类型[数组大小];
elementType[] arrayRefVar = new elementType[arraySize];

//元素类型 数组引用变量[] =new 元素类型[数组大小];
elementType arrayRefVar[] = new e1ementType[arraySize];

注意:一个数组变量看起来似乎是存储了一个数组,但实际上它存储的是指向数组的引用。严格地讲,一个数组变量和一个数组是不同的。为了简化,通常认为数组变量是一个数组,而不是一个数组的引用变量。

访问数组元素

当给数组分配空间时,必须指定该数组能够存储的元素个数,从而确定数组大小。创建数组之后就不能再修改它的大小。可以使用 arrayRefVar.length 得到数组的大小。

当创建数组后,它的元素被赋予默认值。数值型基本数据类型的默认值为 0 ,char 型的默认值为为 ‘\uOOOO’ ,boolean 型的默认值为 false 。

数组元素可以通过下标访问。数组下标是基于 0 的,其范围从 0 开始到 arrayRefVar.length-1 结束。
Java 语言使用方括号引用数组元素。
数组中的每个元素都可以使用下面的语法表示,称为下标变量 (indexed variable) 。

//数组引用变量[下标];
arrRefVar[index];

创建数组后,下标变量与正常变童的使用方法相同。

数组初始化

Java 有一个简捷的标记,称作数组初始化语法,它使用下面的语法将声明数组、创建数组和初始化数组结合到一条语句中:

//元索类型[] 数进引用变量={值 0,值 1,···,值 k};
elementType[] arrayRefVar = {value O, value l,···, value k};

数组初始化语法中不使用操作符 new 。使用数组初始化语法时,必须将声明、创建和初始化数组都放在一条语句中,将它们分开会产生语法错误。

一般语法:

//元索类型[] 数进引用变量={值 0,值 1,···,值 k};
elementType[] arrayRefVar = new elementType[]{value O,value l,···,value k};

处理数组元素是,经常会用到for循环,这是因为:
1.数组中所有元素都是同一类型的;
2.数组大小已知。

foreach循环

Java 支持一个简便的 for 循环,称为 foreach 循环,即不使用下标变量就可以顺序地遍历整个数组。

for(elementType element:arrayRefVar)
{
	System.out.println(element);
}

此代码可以读作 “对 arrayRefVar 中每个元素 element 进行以下操作” 。注意,变量 element 必须声明为与 arrayRefVar 中元素相同的数据类型。
当需要以其它顺序遍历数组或改变数组中的元素时,还是必须使用下标变量。

警告:

  1. 越界访问数组是经常会出现的程序设计错误,它会抛出一个运行错误 ArraylndexOutOfBoundsException。为了避免错误的发生,应确保所使用的下标不超过arrayRefVar.length-1 。
  2. 数组的第一个元素的下标应该是 0 ,但经常错误地使用下标 1 引用数组的第一个元素。它是在循环中该使用 < 的地方误用 <= 时会犯的错误。这被称为下标过 1 错误 (off-by-one error) 。

数组的复制

将一个数组中的内容复制到另外一个数组中,需要将数组的每个元素复制到另外一个数组中。

在程序中经常需要复制一个数组或数组的一部分。这种情况下,你可能会尝试使用賦值
语句 (=) , 如下所示:

list2=listl;

该语句并不能将 listl 引用的数组内容复制给 list2 ,而只是将 listl 的引用值复制给了 list2 ,这样 list1 和 list2 都指向同一个数组, list2 原来引用的数组不能再引用,变成了垃圾,被Java虚拟机自动回收(垃圾回收)。

在 Java 中,可以使用赋值语句复制基本数据类型的变量,但不能复制数组。将一个数组量赋值给另一个数组变量,实际上是将一个数组的引用复制给另一个数组变量,这两个数组变量都指向相同的内存地址。

复制数组有三种方法:
1.使用循环语句逐个地复制数组的元素;
2.使用 System 类中的静态方法 arraycopy ;
3.使用 Arrays 类中的静态方法 copyOf ;
4.使用 clone 方法复制数组。

使用 java.lang.System 类的 arraycopy 方法复制数组, arraycopy 的语法如下所示:

System.arraycopy(sourceArray, srcPos, targetArray, tarPos, length);

其中,参数 srcPos 和 tarPos 分别表示在源数组 sourceArray 和目标数组 targetArray 中的起始位置。复制的元素个数由参数 length 指定。arraycopy 方法没有给目标数组分配内存空间,复制前必须创建目标数组以及分配给它的内存空间。复制完成后,两个数组具有相同的内容,但占有独立的内存空间。
注意: arraycopy 方法违反了 Java 命名习惯 (字母 C 应该大写) 。

使用 java.util.Arrays 类的 copyOf 方法复制数组, copyOf 的语法如下所示:

targetArray=Arrays.copyOf(sourceArray, newLength);

由源数组 sourceArray 向目标数组 targetArray 复制,复制的元素个数由参数 newlength 指定。

将数组传递给方法

当将一个數组传递给方法时,數组的引用被传给方法。
使用下述语法创建数组:

new elementType[]{value O, value l, ···, value k};

该数组没有显式地引用变量,这样的数组称为匿名数组 (anonymous array) 。

Java 使用按值传递 (pass-by-value) 的方式将实参传递给方法。

传递基本数据类型变量的值与传递数组值不同:

  1. 对于基本数据类型参数,传递的是实参的值。
  2. 对于数组类型参数,参数值是数组的引用,给方法传递的是这个引用。从语义上来讲,就是参数传递的是共享信息 (pass-by-sharing) , 即方法中的数组和传递的数组是一样的。把数组的引用传递给方法,数组变量在方法内和方法外都指向在同一内存位置中的同一个数组。所以,如果改变方法中的数组,方法外的数组也随之变化。

注意:数组在 Java 中是对象。 JVM 将对象存储在一个称作堆 (heap) 的内存区域中,堆用于动态内存分配。

从方法中返回数组

可以在调用方法时向方法传递一个数组。方法也可以返回一个数组。当从方法中返回一个数组时,数组的引用被返回。

可变长参数列表

具有同样类型的可变长度的参数可以传递给方法,并将作为数组对待。
可以把类型相同但个数可变的参数传递给方法。方法中的参数声明如下:

//类型名...参数名
typeName...parameterName

在方法声明中,指定类型后紧跟着省略号 (···) 。只能给方法中指定一个可变长参数,同
时该参数必须是最后一个参数。任何常规参数必须在它之前。

Java 将可变长参数当成数组对待,可以将一个数组或数目可变的参数传递给可变长参数。当用数目可变的参数调用方法时, Java 会创建一个数组并把参数传给它。

数组查找

如果一个数组排好序了,对于寻找数组中的一个元素,二分查找比线性查找更加高效。

査找 (searching) 是在数组中寻找特定元素的过程。
査找是计算机程序设计中经常要完成的任务。有很多用于査找的算法和数据结构。两种经常使用的方法:线性查找 (linear searching) 和二分查找 (binary searching) 。

线性查找法
线性査找法将要査找的关键字 key 与数组中的元素逐个进行比较。这个过程持续到在列表中找到与关键字匹配的元素,或者査完列表也没有找到关键字为止。如果匹配成功,线性査找法返回与关键字匹配的元素在数组中的下标。如果没有匹配成功,则返回 -1 。

线性査找法把关键字和数组中的每一个元素进行比较。数组中的元素可以按任意顺序排列。平均来看,如果关键字存在,那么在找到关键字之前,必须与数组中一半的元素进行比较。线性査找法的执行时间随着数组元素个数的增长而线性增长。所以,对于大数组而言,线性査找法的效率并不高。

二分查找法
二分査找法是另一种常见的对数值列表的査找方法。使用二分査找法的前提条件是数组中的元素必须已经排好序。假设数组已按升序排列。二分査找法首先将关键字与数组的中间元素进行比较。
考虑下面三种情况:

  • 如果关键字小于中间元素,只需要在数组的前一半元素中继续査找关键字。
  • 如果关键字和中间元素相等,则匹配成功,査找结束。
  • 如果关键字大于中间元素,只需要在数组的后一半元素中继续査找关键字。

显然,二分法在每次比较之后就排除掉一半的数组元素,有时候是去掉一半的元素,有时候是去掉一半加 1 个元素。

假设数组有 n 个元素。为方便起见,假设 n 是 2 的幂。经过第 1 次比较,只剩下 n/2 个元素需要进一步査找;经过第 2 次比较,剩下(n/2)/2 个元素需要进一步査找。经过 k 次比较之后,需要査找的元素就剩下 n/(2^k) 个。当 k=log(2)n 时,数组中只剩下 1 个元素,就只需要再比较 1 次。因此,在一个已经排序的数组中用二分査找法査找一个元素,即使是最坏的情况,也只需要 log(2)n+l 次比较。
每次比较后,数组要査找的部分就会缩小一半。用 low 和 high 分别表示当前査找数组的第一个下标和最后一个下标。初始条件下,low 为 0 ,而 high 为 list.length-1 。让 mid 表示列表的中间元素的下标。这样,mid 就是(low + high)/2。

Java 实现二分查找:
它将关键字 key 和低下标 low 为 0 、髙下标 high 为 list.length-1 的列表的中间元素进行比较。如果 key<list[mid] ,就将下标 high 设置为 mid-1 ;如果 key==list[mid] ,则匹配成功并返回 mid; 如果 key>list[mid] ,就将下标 low 设置为 mid+1 。接下来要增加一个循环,实现这个方法重复地完成査找。如果找到这个关键字,或者当 low>high 时还没有找到这个关键字,就结束这个査找。

如果列表中有重复的元素,只要列表中的元素是按递增顺序排列的。如果査找的元素在列表中,那么该方法就返回匹配元素中的一个下标。

当没有找到这个关键字时, low 就是一个插入点,这个位置将插入关键字以保持列表的有序性。一种更实用的方法是返回插入点减去 1 。这个方法必须返回一个负值,表明这个关键字不在该序列中。一个好的选择是,如果关键字不在该序列中,方法返回 -low-1 。返回不仅表明关键字不在序列中,而且还给出了关键字应该插人的地方。

**注意:**线性查找法适用于在较小数组或没有排序的数组中查找,但是对大数组而言效率不高。二分查找法的效率较高,但它要求数组已经排好序。

数组的排序

如同查找一样,排序时计算机编程中非常普遍的一个任务。对于排序已经开发出很多不同的算法。

Arrays 类

java.util.Arrays 类包含一些实用的方法用于常见的數组操作,比如排序和查找。

java.util.Arrays 类包括各种各样的静态方法,用于实现数组的排序和査找、数组的比较和填充数组元素,以及返回数组的字符串表示。这些方法都有多所有基本类型的重载方法。

可以使用 sort 或者 parallelSort 方法对整个数组或部分数组进行排序。如果计算机有多个处理器,那么 parallelSort 将更加有效。
可以采用二分査找法 (binarySearch 方法)在数组中査找关键字。数组必须提前按升序排列好。如果数组中不存在关键字,方法返回 -(插入点下标 +1) 。

可以采用 equals 方法检测两个数组是否相等。如果它们的内容相同,那么这两个数组相等。

可以使用 fill 方法填充整个数组或部分数组。

可以使用 toString 方法来返回一个字符串,该字符串代表了数组中的所有元素。这是一个显示数组中所有元素的快捷和简便的方法。

命令行参数

main 方法可以从命令行接收字符串参数。

main 方法的声明具有 String[] 类型参数 args 。参数 args 是一个字符串数组。 main 方法就像一个带参数的普通方法。可以通过传递实参来调用一个普通方法。也可以给 main 传递参数。main 方法就和普通方法一样。此外,还可以从命令行传送参数。

向 main 方法传递字符串:
下面的命令行用三个字符串 argO、argl、arg2 启动程序 TestMain:

java TestMain argO argl arg2

其中,参数 argO 、argl 和 arg2 都是字符串,但是在命令行中出现时,不需要放在双引号中。这些字符串用空格分隔。如果字符串包含空格,那就必须使用双引号括住。

当调用 main 方法时, Java 解释器会创建一个数组存储命令行参数,然后将该数组的引用传递给 args 。例如,如果调用具有 n 个参数的程序, Java 解释器创建一个如下所示的数组:

args = new String[n];

然后,Java 解释器传递参数 args 去调用 main 方法。

如果运行程序时没有传递字符串,那么使用 new String[0] 创建数组。在这种情况下,该数组时长度为0的空数组, args 是对这个空数组的引用。因此,args 不是 null,但是 args.1ength 是 0。

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值