Java 数组

数组是Java中的容器对象, 所谓容器是数据的容器, 而这个容器(即数组)自身就是一个对象, 所以叫做容器对象. 数组具有以下两个主要特点:

  • 类型单一 是指容器内部的数据的类型是单一的, 容器只能存放同一类数据
  • 数量固定 是指容器在创建的时候就确定了内部数据的数量

之前的教程, 我们或多或少的接触过一些数组的用法, 本节将做进一步的详细介绍. 首先为了便于理解数组这个容器的构造, 来看一个数组的图片, 来便于我们理解:

Java 数组

(一个长度为10的数组)

数组中的每一个项目我们称之为元素, 数组中的元素通过索引来访问, 索引就是元素的序号, 这是一组从0开始到数组的长度-1的整数序列, 这就意味着数组的访问是从0开始的. 以图中为例, 当我们访问索引为 7 的元素的时候, 实际上访问的是数组的第 8 个元素.

以下, 我们将通过一个例子来看数组的使用.

示例代码A:

public class Yi21Array {
    public static void main(String[] args) {
        //声明一个数组变量
        int[] intArray;
        //初始化一个数组: 为数组分配内存. 也可以直接写作 int[] intArray = new int[5];
        intArray = new int[5];
        //初始化第一个元素的值, 数组的索引是从0开始
        intArray[0] = 0;
        //初始化第二个元素的值
        intArray[1] = 5;
        intArray[2] = 10;
        intArray[3] = 15;
        //元素的值可以重复
        intArray[4] = 0;
        System.out.println("索引为0的第1个元素: " + intArray[0]);
        System.out.println("索引为1的第2个元素: " + intArray[1]);
        System.out.println("索引为2的第3个元素: " + intArray[2]);
        System.out.println("索引为3的第4个元素: " + intArray[3]);
        System.out.println("索引为4的第5个元素: " + intArray[4]);
        // 超过数组的索引的上限会, 抛出异常
        // System.out.println("索引为4的第5个元素: " + intArray[5]);
    }
}

输出的结果为:

索引为0的第1个元素: 0
索引为1的第2个元素: 5
索引为2的第3个元素: 10
索引为3的第4个元素: 15
索引为4的第5个元素: 0

声明并初始化数组的方法

数组的声明方式如下:

类型[] 变量名;

正如示例A中的声明, 我们首先声明了一个存放 int 的数组:

int[] intArray;

然后通过 new 关键词, 初始化一个带数量参数的数组来完成初始化:

intArray = new int[5];

初始化完成后再依次给元素赋值, 因为是存放 int 的数组, 所以我们给元素赋值也必然是int类型的:

intArray[0] = 0;
intArray[1] = 5;

我们同样可以声明 char[], float[], String[] 以及其他类的数组.

定义时赋值

因为数组的强大且有用, 所以 Java 在语法层面对数组做了很多支持, 比如直接通过特定的格式来生成一个数组, 示例如下:

String[] names = {"21yi", "Baidu", "Ali", "Tencent"};

在上述示例中, 我们使用了一对花括号 {} 来包裹多个字符串元素生成了一个字符串数组, 很显然这个字符串数组拥有4个元素.

数组的遍历

所谓遍历, 就是一个一个经历一次, 数组的遍历也就是指把数组的每个元素都拿出来做某些我们定义的操作.

数组的强大性的一部分体现在易于遍历, 通过循环我们可以处理一个具有相当数量元素的数组, 来做相似的操作.

我们通过学习 for 语句的章节了解到, 可以通过确定数组的长度来遍历数组, 示例如下:

String[] sites = {"21yi", "Baidu", "Ali", "Tencent"};
for (int i = 0; i < sites.length; i++) {
    System.out.println(sites[i]);
}

通过 sites 变量获取数组的长度, 累加索引值来实现遍历.

我们同样的还能通过 for(:) 的形式来遍历数组, 示例代码如下:

String[] names = {"刘备", "诸葛亮", "关羽", "张飞", "赵云", "黄忠", "魏延"};
for(String name: names) {
    System.out.println(name);
}

上面就是局部变量 name 通过 for 中的 : 带入到数组 names 中实现遍历.

多维数组

所谓多维数组, 就是数组中的每个元素都是个数组的数字, 维是维度的意思. 需要注意的是, Java 的多维数组允许元素数组的长度不一致, 示例代码如下:

public class Yi21Array2 {
    public static void main(String[] args) {
        String[][] names = {
            {"哥", "姐"},
            {"赵", "钱", "孙", "李"},
        };
        System.out.println("你好, " + names[1][2] + names[0][1]);
        System.out.println("你好, " + names[1][0] + names[0][0]);
    }
}

在上面的代码中, 我们定义了一个有关称呼的二维数组, 数组的第1个元素是有关称谓的数组, 第2个元素是有关姓氏的数组.

当我们需要调用姓氏数组时, 我们首先通过 names[1] 找到姓氏数组, 然后通过索引找到自己想要的姓氏. 称谓亦然.

比如我们要配对出 孙姐赵哥 两个称谓.

孙姐: 孙(姓氏的第 3 个元素) + 姐(称谓的第2个元素) -> names[1][2] + names[0][1]

赵哥: 赵(姓氏的第 1 个元素) + 哥(称谓的第1个元素) -> names[1][0] + names[0][0]

因此上述代码的执行结果也就是:

孙姐
赵哥

复制数组

正如 Java 的其他类型, 给变量赋值, 其实是将数组的地址交给变量来引用. 因此当我们想将一个数组复制一份, 来进行其他操作的时候, 我们需要用一个特殊的方法 System.arraycopy() 用法如以下示例代码:

public class Yi21CopyArray {
    public static void main(String[] args) {
        char[] copyFrom = { 'm', 'j', '3', '5', 'z', 'a', '2', '1', 'y', 'i', 'k', 'f', 'g' };
        char[] copyTo = new char[8];
        copyTo[4] = '.';
        copyTo[5] = 'c';
        copyTo[6] = 'o';
        copyTo[7] = 'm';
        System.arraycopy(copyFrom, 6, copyTo, 0, 4);
        System.out.println(new String(copyTo));
    }
}

从上面我们可以看出 System.arraycopy() 可以复制数组的指定部分, 可以设置复制源的起始位置, 也可以指定复制目标的索引和拷贝的长度.

上述方法的就是从 copyFrom 的索引 6 开始拷贝, 将值填充到 copyTo 的从索引0开始的4个元素中去. 所以上述代码的执行结果为:

21yi.com

数组的操控

Java SE 通过 java.util.Arrays 工具包, 为数组提供了很多强大的操控方法. 比如我们可以用它的 copyOfRange 方法直接复制出我们想要的区间作为一个新的数组来使用, 比如我们在上面的代码 main 方法的结尾添加以下代码:

char[] copyTo2 = java.util.Arrays.copyOfRange(copyFrom, 6, 10);
System.out.println(new String(copyTo2));

我们仍然可以获得一个 21yi 的输出.

java.util.Arrays 还提供了一些其他有用的方法:

binarySearch: 在数组中搜索特定值以获取放置它的索引.

equals: 比较两个数组以确定它们是否相等.

fill: 将特定值填充到数组的每个索引下.

sort: 将数组按升序排序

parallelSort: Java SE 8中引入的并行排序方法, 多处理器系统上处理大型数组通常比 sort 要快.

以下是详细的 Arrays 方法列表:

序号 类型 名称 说明
1 方法 Arrays.toString()

将数组的内容转换成字符

2 方法 Arrays.stream()

获取一个以指定数组作为源的 Stream .

3 方法 Arrays.spliterator()

获取一个覆盖数组全部的 Spliterator

4 方法 Arrays.sort()

根据类型将指定的数组或指定数组的范围按升序排序

5 方法 Arrays.setAll()

使用提供的生成器函数计算并设置指定数组的每个元素

6 方法 Arrays.parallelSort()

根据类型并行将指定的数组或指定数组的范围按升序排序

7 方法 Arrays.parallelSetAll()

使用提供的生成器函数并行计算并设置指定数组的每个元素

8 方法 Arrays.parallelPrefix()

使用提供的函数并行累加给定数组或给定数组范围的每个元素

9 方法 Arrays.mismatch()

查找并返回两个数组之间第一个不匹配的元素的索引

10 方法 Arrays.hashCode()

获取数组的哈希值

11 方法 Arrays.fill()

用指定的元素值填充到数组的每一个元素

12 方法 Arrays.equals()

判断两个数组是否相等

13 方法 Arrays.deepToString()

将数组的深度内容转换成字符

14 方法 Arrays.deepHashCode()

基于深度内容计算数组的哈希值

15 方法 Arrays.deepEquals()

判断两个指定的数组是否彼此深度相等

16 方法 Arrays.copyOfRange()

将指定数组的指定范围复制到新数组中

17 方法 Arrays.copyOf()

复制指定的数组, 用 false 截断或在必要的情况下填充, 进而使得复制的数组具有指定的长度

18 方法 Arrays.compareUnsigned()

无符号比较两个整型( byte, short, int, long).

注意: 无符号的意思不是求一个负数的绝对值.

19 方法 Arrays.compare()

比较两个数组

20 方法 Arrays.binarySearch()

使用二进制查找算法在指定的长整型数组中查找指定值

21 方法 Arrays.asList()

生成一个 List 

下一节, 请看 Java 的数字与数学处理