思维导图:
2.7.1 数组的基本要素
### 2.7 数组
数组在编程中是一种重要的数据结构,用于存储一系列的数据。特别是当处理大量相似类型的数据时,数组的效用尤为显著。
#### 2.7.1 数组的基本要素
一个数组主要由以下四个基本元素构成:
1. **数组名称**:用于标识数组的唯一标识。
2. **数组元素**:存储在数组中的数据。
3. **元素索引**:表示数组元素位置的数字。在Java中,索引始于0。
4. **数据类型**:数组中存储的所有元素的数据类型。
在Java中声明一个数组的基本格式如下:
数据类型[]数组名;
数组名 = new 数据类型[长度];
例如,要声明一个可以存储100个整数的数组,可以这样写:
int[] x;
x = new int[100];
这样的声明方式意味着在内存中为`x`分配了100个连续的整数存储空间。默认情况下,这100个整数的初值都是0。
#### 2.7.2 数组在内存中的表示
当声明一个数组变量(例如上面的`x`)时,实际上创建了一个指向数组的引用。这个引用本身也是存储在内存中的。当使用`new`关键字实际创建数组时,会在内存中为该数组分配相应的空间。
考虑上面的例子,首先声明了一个数组引用`x`,它的初始状态如图2-39所示。接着,为它分配100个整数的存储空间。此时,`x`的状态如图2-40所示,它指向这100个整数的首地址。
要访问数组中的元素,可以使用如`x[0]`、`x[1]`...的方式。这里的数字称为数组的索引或下标。重要的是要记住,数组的索引始于0,所以一个长度为100的数组的最后一个元素的索引是99。
为了方便获取数组的长度,Java提供了一个名为`length`的属性。可以通过`数组名.length`的方式来获得。
#### 小结
使用数组可以简化存储和处理大量数据的复杂性。通过上面的知识,我们知道了如何在Java中声明、初始化和访问数组,以及如何获取数组的长度。这为后续的数组操作和处理提供了基础。
2.7.2 数组的简单使用
### 2.7.2 数组的简单使用
数组在Java中的使用是相当直观和简单的。下面我们通过一个示例来了解如何定义、初始化和访问数组。
#### 示例:Example22.java
public class Example22 {
public static void main(String[] args) {
// 声明数组变量
int[] arr;
// 创建数组对象并分配空间
arr = new int[3];
// 访问数组中的各个元素
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.length);
}
}
在上述代码中,`arr`是一个整数类型的数组。它首先被声明,然后创建了一个长度为3的整数数组。随后,程序访问数组的每个元素并打印其值。最后,我们打印了数组的长度。
注意,在这个示例中,我们没有为数组的元素显式地赋值。所以,当我们尝试访问数组中的元素时,它们都显示为默认值0(对于整数数组来说)。
#### 结果
运行这段代码会得到以下的输出:
arr[0] = 0
arr[1] = 0
arr[2] = 0
数组的长度是:3
这里要注意的是,当我们声明并初始化一个新的数组但没有为它的元素分配值时,Java会为数组中的每个元素提供一个默认值。对于基本数据类型,如整数,默认值是0。对于对象,如String,默认值是null。
#### 小结
通过这个简单的例子,我们了解了如何在Java中声明、初始化和访问数组。使用数组,我们可以轻松地存储和操作大量数据,这对于编程中的许多任务来说都是非常有用的。
### 2:7.2 数组的简单使用
**1. 定义数组**
数组是一个容器,可以存储多个相同类型的元素。数组中每个元素都有一个自动编号,也叫做索引或下标,最小索引是0,最大索引是数组长度减1。
- **动态初始化**: 仅定义数组长度,系统会为数组元素自动赋初值。
int[] arr = new int[3];
- **静态初始化**: 定义数组的时候同时为数组元素赋值。
int[] arr = {1, 2, 3, 4};
或
int[] arr = new int[]{1, 2, 3, 4};
**注意**: 第二种静态初始化方式更为简洁。
**2. 访问数组元素**
可以通过数组名加索引的方式访问数组元素。
System.out.println(arr[0]);
**3. 数组的属性**
System.out.println("数组的长度是:" + arr.length);
**4. 默认初始化值**
不同的数据类型的数组元素,系统赋予的默认值不同:
数据类型 | 默认值 |
---|---|
byte、short、int、long | 0 |
float、double | 0.0 |
char | 一个空字符,即`\u0000` |
boolean | false |
引用数据类型 | null |
**5. 赋值**
除了使用默认值外,也可以显式地为数组的每个元素赋值。
arr[0] = 1;
arr[1] = 2;
**6. 注意事项**
- 当访问数组的元素时,索引不能超出0~length-1的范围,否则会出现索引越界的错误。
- 静态初始化时,不能同时指定数组的长度和为数组的元素赋值,如`int[]arr =new int[4]{1,2,3,4}`,这样的写法是错误的。
**示例**:
文件`Example22.java`展示了如何定义一个整数类型的数组,给数组的元素赋值以及访问数组的元素。
文件`Example24.java`展示了数组的静态初始化方式。
文件`Example25.java`尝试访问一个超出范围的数组索引,会导致运行时异常。
2.7.3 数组的常见操作
### 2.7.3 数组的常见操作
数组在编程中的应用极为广泛。对数组的操作不仅仅局限于声明、初始化和简单的数据访问,还包括更复杂的遍历、搜索、排序和插入等操作。
**1. 数组的遍历**
- 为了访问数组中的每一个元素,我们经常会使用循环结构进行遍历。`for`循环是常用的遍历手段。例如:
int[] arr = {1, 2, 3, 4, 5};
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
**2. 异常操作**
- **数组越界异常**:在尝试访问数组的一个不存在的索引时,会触发`ArrayIndexOutOfBoundsException`。如在长度为4的数组中尝试访问索引4。
- **空指针异常**:当一个数组引用被设置为`null`(意味着它不再引用任何数组对象)后,再试图通过这个引用访问数组的元素,会引发`NullPointerException`。
**示例**:
在文件`Example26.java`中,我们首先创建了一个大小为3的数组,并为其第一个元素赋了值。在访问该数组的元素后,我们将数组的引用置为`null`,然后再次尝试访问数组的元素,结果就是一个`NullPointerException`。
int[] arr = new int[3]; //定义一个长度为3的数组
arr[0] = 5; //为数组的第一个元素赋值
System.out.println("arr[0]=" + arr[0]); //访问数组的元素
arr = null; //将变量arr置为null
System.out.println("arr[0]=" + arr[0]); //再次访问数组的元素时会引发空指针异常
在处理数组时,为避免此类异常,建议:
1. 时刻检查数组的边界。
2. 在使用数组引用前进行非空检查。
**小结**: 数组是Java中的基础数据结构,熟练掌握其操作和相关注意事项是每个Java程序员的必备技能。
## 2.7.3 数组的常见操作
**简介**:
数组是Java中最基本的数据结构之一,用于存储同一类型的多个元素。以下是对数组进行的一些常见操作。
### 1. 数组的遍历
**定义**:
遍历是一种基本操作,它允许我们访问数组中的每一个元素。
**示例**:
public class Example27 {
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4, 5};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
- 注意:数组的索引范围是0到数组长度减1。
### 2. 数组中最值的获取
**定义**:
这涉及到在数组中查找最大或最小值。
**示例**:
public class Example28 {
public static void main(String[] args) {
int[] arr = {4, 1, 6, 3, 9, 8};
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println("数组arr中的最大值为:" + max);
}
}
### 3. 在数组的指定位置插入一个数据
**定义**:
因为数组的大小是固定的,所以在插入新的数据时,我们需要创建一个新的更大的数组,然后将旧数组的数据复制到新数组中。**示例**:
public class Example29 {
public static void main(String[] args) {
int[] arr = {10, 11, 13, 14, 15};
int score = 12;
int[] arr2 = new int[arr.length + 1];
for (int i = 0; i < 3; i++) {
arr2[i] = arr[i];
}
arr2[2] = score;
for (int i = 3; i < arr2.length; i++) {
arr2[i] = arr[i-1];
}
System.out.print("添加新元素之前的arr数组:");
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + ",");
}
System.out.println("");
System.out.print("添加新元素之后的arr2数组:");
for (int i = 0; i < arr2.length; i++) {
System.out.print(arr2[i] + ",");
}
}
}
这些是对数组进行的几种基本操作,对于复杂的操作和算法,可能需要使用其他数据结构或Java提供的工具类。
**4.数组排序**
**冒泡排序简介**:
在日常编程开发中,排序是数组中最常用的操作。Java提供了多种数组排序算法,其中一种常见的是冒泡排序。
冒泡排序的基本思想是:通过不断地比较相邻元素的大小,使小的数像“气泡”一样“浮”到上面,而大的数则“沉”到下面。这个过程类似于气泡在水中不断上浮的过程。
**冒泡排序步骤分析**:
1. **第一步**:从第一个元素开始,对每对相邻的元素进行比较。如果前一个元素大于后一个元素,则交换它们的位置。完成这一轮后,最大的元素会被放在数组的最后一个位置。
2. **第二步**:忽略最后一个元素,再次对剩下的元素进行两两比较,把第二大的元素放在倒数第二的位置。
3. **第三步**:这样一直继续,直到没有元素需要比较为止。
**Java代码示例**:
文件名:`Example30.java`
public class Example30 {
public static void main(String[] args) {
int[] arr = {9, 8, 3, 5, 2};
// 冒泡排序前,打印数组元素
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
System.out.println();
// 开始冒泡排序
for (int i = 1; i < arr.length; i++) {
for (int j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
// 交换两个元素
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
// 冒泡排序后,打印数组元素
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
**两个元素的交换**:数组中两个元素的交换过程在上述代码中的第16至18行。具体步骤如下:
1. 使用临时变量`temp`保存一个元素的值。
2. 将另一个元素的值赋给第一个元素。
3. 最后,将临时变量`temp`的值赋给第二个元素。
这样,两个元素的值就交换了位置。
**总结**:
冒泡排序是排序算法中的基础算法之一,它的原理简单、容易实现,但在大规模数据中的效率不如其他高级排序算法。在学习数据结构和算法时,了解并掌握冒泡排序是非常必要的。
2.7.4 二维数组
# 2.7.4 二维数组
## 介绍
在程序中,仅使用一维数组是远远不够的。例如,统计一个学校各个班级的学生成绩,需要同时标识班级和学生成绩,此时使用一维数组是不足够的。为此,多维数组被引入,它可以简单地理解为数组中的数组。其中,二维数组是最常见的,它具有两个索引,用于表示行和列。
## 定义
二维数组可以用多种方式定义,以下介绍三种常见方法:
1. **固定行和列的二维数组**
```java
数据类型[][] 数组名 = new 数据类型[行数][列数];
```
例如:
```java
int[][] xx = new int[3][4];
```
这会创建一个3行4列的二维数组。
2. **确定行数,但列数不确定的二维数组**
```java
数据类型[][] 数组名 = new 数据类型[行数][];
```
例如:
```java
int[][] xx = new int[3][];
```
3. **使用具体的元素值来定义二维数组**
```java
数据类型[][] 数组名 = {{第0行元素}, {第1行元素}, ..., {第n行元素}};
```
例如:
```java
int[][] xx = {{1, 2}, {3, 4, 5, 6}, {7, 8, 9}};
```
## 访问元素
要访问二维数组中的某个元素,使用以下格式:
```java
数组名[行索引][列索引]
```
例如,访问`xx`数组的第一个元素的第二个值:
```java
xx[0][1];
```
## 示例
以下示例展示了如何使用二维数组统计一个公司3个销售小组的销售额:
public class Example31 {
public static void main(String[] args) {
//定义一个长度为3的二维数组
int[][] arr = new int[3][];
//为数组的元素赋值
arr[0] = new int[]{11, 12};
arr[1] = new int[]{21, 22, 23};
arr[2] = new int[]{31, 32, 33, 34};
//定义变量记录公司总销售额
int sum = 0;
//遍历数组元素
for (int i = 0; i < arr.length; i++) {
int groupSum = 0; //小组销售额
for (int j = 0; j < arr[i].length; j++) {
groupSum += arr[i][j];
}
sum += groupSum; //累加小组销售额到总销售额
System.out.println("第" + (i + 1) + "小组销售额为:" + groupSum + "万元。");
}
System.out.println("总销售额为:" + sum + "万元。");
}
}
## 总结
二维数组是一个强大的数据结构,它为存储和管理表格形式的数据提供了方便。在Java中,可以使用多种方式来定义和初始化它们,并通过行和列索引来访问其元素。
总结:
以下是关于Java中数组的总结:
### 重点:
1. **数组的定义与初始化**:Java中的数组是一个引用数据类型,可以存储多个同类型的数据。可以通过静态初始化和动态初始化进行定义和赋值。
2. **二维数组**:在Java中,可以有多维数组,但最常用的是二维数组。理解它如何工作,特别是如何通过两个索引来访问元素,是至关重要的。
3. **数组的属性**:每个数组都有一个属性`length`,代表数组的长度。
### 难点:
1. **多维数组**:理解和操作多维数组可能需要时间。尤其是在内部循环中使用多维数组可能会使一些初学者感到困惑。
2. **数组的内存表示**:理解数组是如何在内存中存储的,以及如何与数组引用和实际的数组对象进行交互,可以帮助更深入地理解Java中的数组。
3. **数组的边界**:在处理数组时,超出其边界是一个常见的错误。
### 易错点:
1. **越界访问**:尝试访问数组的非法索引(通常小于0或大于等于`length`)会导致`ArrayIndexOutOfBoundsException`。
2. **空引用访问**:未初始化的数组引用可能导致`NullPointerException`。
3. **误解数组长度**:常常与新手混淆的是,`array.length`给出的是数组的长度,而不是最后一个元素的索引。
### 使用技巧:
1. **增强型for循环**:使用增强型for循环(也称为“for-each”循环)可以更简洁地遍历数组。
```java
for(int value : array) {
System.out.println(value);
}
```
2. **工具类**:Java的`Arrays`类提供了许多有用的数组操作方法,如`sort()`, `toString()`, `fill()`, `binarySearch()`等。
3. **数组拷贝**:可以使用`System.arraycopy()`或`Arrays.copyOf()`来复制数组。
4. **变长参数**:当定义方法时,可以使用变长参数来接受任意数量的参数。这实际上是一个数组,可以在方法体内像数组一样使用它。
总之,Java中的数组是一个强大的数据结构,但也需要注意边界和空引用问题。通过理解它们如何在内部工作,以及使用Java提供的工具和技巧,可以更有效地使用数组。