数组的定义和使用大多和C是一样的。数组是存放一类数据的一种数据结构。Java中的数组（Array）是一种特殊的对象（通过类实例化），也有特殊的语法结构。在学习Array的时候，请注意其语法，以及与后续类和对象的区别。

## 1. 声明与使用

### 1.1. 声明与使用数组

下面这个例子说明了数组的基本使用。

```java
public class ArrayTest {

    public static void main(String[] args) {
        int[] myList;

        myList = new int[2];
        myList[0] = 0;
        myList[1] = 1;

        System.out.println(myList[1]);

        myList = new int[3];

        System.out.println(myList[1]);

    }
}
```

Java中数组的声明与使用与C类似，`int[] myList`  定义了一个可以存放int数据类型的数组，但是此时还没有为这个数组分配内存。这一点和C的指针类似，其实myList这个变量叫做引用变量，也和指针类似。

要为myList这个数组分配内存，使用 `new int[2]` 这种类似的语法。该语法返回一个数组对象的引用地址，数组的容量是2，并赋值给引用变量 myList，然后就可以通过引用变量 myList对数组进行操作了。

可以重复对一个数组引用变量使用new语句分配内存，例如，例子中第6行和第12行。与C不同的是，Java不用对动态分配的内存进行回收。

 

**特别注意这里new的语法结构，后面是数组定义时的类型，大小设置不是圆括号，而是方括号！**

### 1.2. 声明和分配内存在一行中

```java
public class ArrayTest2 {

    public static void main(String[] args) {
        int[] myList = new int[2];

        myList[0] = 0;
        myList[1] = 1;

        System.out.println(myList[1]);
    }

}
```

### 1.3. 在声明的同时初始化数组

这个语法结构和C类似：

```java
public class ArrayTest3 {

    public static void main(String[] args) {
        int[] myList = {1,3,5,7};
        System.out.println(myList[1]);
    }

}
```

**注意，大括号赋初值的语法只能在数组声明中使用，不能单独使用。**

### 1.4. 数组元素的缺省值

When an array is created, its elements are assigned the default value of 

0 for the numeric primitive data types, 
'\u0000' for char types, and 
false for boolean types. 

## 2. 数组操作

### 2.1. 数组对象上的操作

数组本质上是一个对象，因此直接可以在数组的引用变量上对数组进行操作。例如，取得数组的长度：

```java
public class ArrayTest2 {

    public static void main(String[] args) {
        int[] myList = {1,3,5,7};
        System.out.println(myList.length);
    }

}
```

myList 作为一个对象，还有很多实例函数，只需要在IDE中写入这个引用变量，并在后面打一个点，就会出现这个对象的所有操作（可能包括变量、函数和常量）。

![](img/2023-03-04-13-50-32-image.png)

有兴趣的可以研究一下这些函数的作用，其实从这些函数名就可以知道大约的作用。

### 2.2. 数组元素的初始值

When an array is created, its elements are assigned the default value of 

0 for the numeric primitive data types, 
'\u0000' for char types, and 
false for boolean types. 

### 2.3. 加强的for循环

和C一样，Java数组的下标也是从0开始的；结合数组的长度，可以对数组进行遍历。

```java
public class Test {

    public static void main(String[] args) {
        int arrayInt[] = { 1, 3, 5, 7 };
        for (int i = 0; i < arrayInt.length; i++) {
            System.out.println(arrayInt[i]);
        }
    }

}
```

Java还提供了一种更方便的for循环：

```java
public class ArrayTest2 {

    public static void main(String[] args) {
        int[] myList = { 1, 3, 5, 7 };
        for (int i : myList) {
            System.out.println(i);
        }
    }

}
```

这个加强版的for循环例子如上，myList是一个数组（更准确的说是一个数据集），每次取得一个数据集的元素并保存在变量i中（注意这个临时变量i的类型必须和数组中存放数据的类型一致），直到所有的元素被遍历。

**注意，这个for循环在以后会大量用到。**

### 2.4. 数组变量是引用变量（指针）

![](img/20230304124145.png)

对数组赋值，会改变引用变量的内存指向，这和C的指针是一个概念。

**注意：Java中不存在手动回收内存，不存在指针悬空的情况。**

### 2.5. 使用函数来复制数组

可以使用循环来复制数组：

```java
public class Test {

    public static void main(String[] args) {
        int[] sourceArray = { 2, 3, 1, 5, 10 };
        int[] targetArray = new int[sourceArray.length];

        for (int i = 0; i < sourceArray.length; i++)
            targetArray[i] = sourceArray[i];
    }

}
```

Java在System这个类中提供了一个更加通用的数组复制函数`arraycopy`，注意这个函数是静态函数。

```java
public class ArrayTest2 {

    public static void main(String[] args) {
        int[] myList1 = { 1, 3, 5, 7 };
        int[] myList2 = new int[10];        
        System.arraycopy(myList1, 0, myList2, 0, 3);
        for (int i : myList2) {
            System.out.println(i);
        }
    }
}
```

注意 System.arraycopy 这个函数的参数代表什么意思。

### 2.6. 数组作为函数参数

```java
public class ArrayTest3 {

    public static void main(String[] args) {
        int[] iA = { 5, 6, 7, 8 };
        System.out.println("The original array:");
        printArray(iA);

        changeVal(iA);
        System.out.println("After change item value in function:");
        printArray(iA);

        changeArray(iA);
        System.out.println("After change array in function:");
        printArray(iA);
    }

    public static void printArray(int[] a) {
        for (int i : a) {
            System.out.println(i);
        }
    }

    public static void changeVal(int[] a) {
        for (int i = 0; i < a.length; i++) {
            a[i] = i;
        }
    }

    private static void changeArray(int[] a) {
        a = new int[3];
        for (int i = 0; i < a.length; i++) {
            a[i] = i + 100;
        }
    }

}
```

**注意：可以在函数中改变数组内部元素的值。**

### 2.7. 对数组元素排序

Arrys这个类中提供对数组进行排序的函数：

```java
public class Test {

    public static void main(String[] args) {

        double[] numbers = { 6.0, 4.4, 1.9, 2.9, 3.4, 3.5 };
        java.util.Arrays.sort(numbers);
        for (double item : numbers)
            System.out.print(item + " ");
    }

}
```

排序后，数组中的元素按照从小到大排列。

### 2.8. 数组元素的查找

我们可以使用循环来查找数组中某个元素的位置，其实Java已经给我们提供了一个数组查找的函数`binarySearch`。注意这里的binary是指二分法排序，而不是指二进制。如果采用二分法查找，那么数组必须是有序的。如果无法确保数组是有序的，使用前面的`java.util.Arrays.sort`函数先对数组进行排序。

```java
public class Test {

    public static void main(String[] args) {
        int[] list = { 2, 4, 7, 10, 11, 45, 50, 59, 60, 66, 69, 70, 79 };
        int pos = -1;
        pos = java.util.Arrays.binarySearch(list, 11);
        System.out.println("Index is " + pos);
    }

}
```

这个函数就是binarySearch，注意这个函数的使用，前面的一串`java.util.Arrays` 不是都指类的名字；最有最后的 `Arrays` 是类名，而 `java.util` 是命名空间。通常情况下，可以简单的理解命名空间就是目录的层级关系。

关于`java.util.Arrays`这个类还有很多其他函数，可以在IDE中通过输入点(.)查看：

![](img/2023-03-04-15-49-20-image.png)

有兴趣的同学可以自己去研究一下。

### 2.9. 补充

这些内容可能考试不会直接考到，但是会方便你的编程，希望你们可以掌握。

关于String的操作，通常会用到把一个字符串转换成数组。例如一个以空格分隔的字符串，我们希望把每一段切取出来，形成一个数组，这时我们使用：

```java
        String string = "AAA BBB CCC";
        string.split(" ");
```

split的参数是一个正则表达式（这个我们可以不用掌握），这里如果字符串是空格分隔，写入一个空格的字符串就可以了，标识拆分的字符串。

函数返回是一个 String\[\] 类型的数组，你得到的是 {"AAA", "BBB", "CCC" } ，注意，不包含分隔字符串。

相对的，可以使用 join 函数把一个字符串数组以一定的分隔符连接成一个新的字符串。

split 是实例函数，join是静态函数。

## 3. 读取命令行参数

细心的同学们可能注意到了，在主函数中有一个字符串的数组，这个是做什么的？其实这是传递程序运行是输入的命令行参数设计的，我们看看下面这个例子：

```java
public class Calculator {
    /** Main method */
    public static void main(String[] args) {
        // Check number of strings passed
        if (args.length != 3) {
            System.out.println("Usage: java Calculator operand1 operator operand2");
            System.exit(0);
        }

        // The result of the operation
        int result = 0;

        // Determine the operator
        switch (args[1].charAt(0)) {
        case '+':
            result = Integer.parseInt(args[0]) + Integer.parseInt(args[2]);
            break;
        case '-':
            result = Integer.parseInt(args[0]) - Integer.parseInt(args[2]);
            break;
        case '.':
            result = Integer.parseInt(args[0]) * Integer.parseInt(args[2]);
            break;
        case '/':
            result = Integer.parseInt(args[0]) / Integer.parseInt(args[2]);
        }

        // Display result
        System.out.println(args[0] + ' ' + args[1] + ' ' + args[2] + " = " + result);
    }
}
```

主函数`void main(String[] args)` 中有有一个args 的字符串数组。编译这个程序，然后在命令行下执行，如果不记得命令行中如何编译和运行Java，请参考第一章中的内容。

![](img/2023-03-04-15-41-18-image.png)

在命令行中运行编译好的代码 `java Calculator 1 + 21` 其中java是运行Java程序的命令，后面的 `Calculator` 是Java编译后的可执行代码；`1 + 21` 是命令行参数。这个参数会传递给Calculator的主程序，通过main函数的args这个字符串数组解析出来。如同Scanner 对象一样，解析这个数组是按照空格区分的，因此，这个例子中我们得到的args数组是：

| 数组元素    | 值   | 说明  |
| ------- | --- | --- |
| args[0] | 1   |     |
| args[1] | +   |     |
| args[2] | 21  |     |

后面的代码就很简单了。

  
## 4. 本章重点

1. 掌握数组的声明和使用；
2. 掌握增强for循环的使用；
3. 理解数组作为函数参数的使用；
4. 其他内容均为了解。