You cannot select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

357 lines
11 KiB
Markdown

This file contains invisible Unicode characters!

This file contains invisible Unicode characters that may be processed differently from what appears below. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to reveal hidden characters.

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

数组的定义和使用大多和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是指虚拟机后面的 `Calculator` 是Java编译后的可执行代码`1 + 21` 是命令行参数。这个参数会传递给Calculator的主程序通过main函数的args这个字符串数组解析出来。如同Scanner 对象一样解析这个数组是按照空格区分的因此这个例子中我们得到的args数组是
| 数组元素 | 值 | 说明 |
| ------- | --- | --- |
| args[0] | 1 | |
| args[1] | + | |
| args[2] | 21 | |
后面的代码就很简单了。
  
## 4. 本章重点
1. 掌握数组的申明和使用;
2. 掌握增强for循环的使用
3. 理解数组作为函数参数的使用;
4. 其他内容均为了解。