Skip to content

数组

数组是一种容器,可以存储多个相同类型的数据。数组在内存中是连续存储的,通过索引可以快速访问元素。

数组概述

text
┌─────────────────────────────────────────────────────────────────┐
│                        数组特点                                 │
├─────────────────────────────────────────────────────────────────┤
│  1. 长度固定:创建后长度不可改变                                 │
│  2. 类型统一:只能存储同一种数据类型                             │
│  3. 连续存储:内存中连续分配空间                                 │
│  4. 索引访问:从 0 开始,最大索引为 length-1                     │
│  5. 引用类型:数组本身是引用类型                                 │
└─────────────────────────────────────────────────────────────────┘

一维数组

数组声明和初始化

java
public class ArrayDeclaration {
    public static void main(String[] args) {
        // 方式一:先声明,后初始化
        int[] arr1;
        arr1 = new int[5];  // 创建长度为 5 的数组
        
        // 方式二:声明时初始化
        int[] arr2 = new int[5];
        
        // 方式三:静态初始化(指定元素)
        int[] arr3 = {1, 2, 3, 4, 5};
        
        // 方式四:静态初始化的完整形式
        int[] arr4 = new int[]{1, 2, 3, 4, 5};
        
        // 字符串数组
        String[] names = {"张三", "李四", "王五"};
        
        // 访问数组元素
        System.out.println("arr3[0] = " + arr3[0]);  // 1
        System.out.println("arr3[4] = " + arr3[4]);  // 5
        
        // 数组长度
        System.out.println("arr3.length = " + arr3.length);  // 5
        
        // 修改数组元素
        arr3[0] = 100;
        System.out.println("修改后 arr3[0] = " + arr3[0]);  // 100
    }
}

数组的内存结构

text
┌─────────────────────────────────────────────────────────────────┐
│                      数组内存结构                                │
├─────────────────────────────────────────────────────────────────┤
│                                                                 │
│   栈内存                    堆内存                              │
│  ┌─────────┐              ┌───────────────────────────┐        │
│  │   arr   │─────────────>│ [0] [1] [2] [3] [4]      │        │
│  │ (引用)   │              │  1   2   3   4   5       │        │
│  └─────────┘              └───────────────────────────┘        │
│                               new int[]{1,2,3,4,5}             │
│                                                                 │
│  数组变量存储的是数组对象的地址(引用)                          │
│  数组对象存储在堆内存中                                         │
└─────────────────────────────────────────────────────────────────┘

数组遍历

java
public class ArrayTraversal {
    public static void main(String[] args) {
        int[] arr = {10, 20, 30, 40, 50};
        
        // 方式一:普通 for 循环
        System.out.println("普通 for 循环:");
        for (int i = 0; i < arr.length; i++) {
            System.out.println("arr[" + i + "] = " + arr[i]);
        }
        
        // 方式二:增强 for 循环(for-each)
        System.out.println("\n增强 for 循环:");
        for (int num : arr) {
            System.out.println("元素: " + num);
        }
        
        // 方式三:使用 Arrays 工具类
        System.out.println("\nArrays.toString:");
        System.out.println(java.util.Arrays.toString(arr));
        
        // 带索引的遍历
        System.out.println("\n带索引遍历:");
        int index = 0;
        for (int num : arr) {
            System.out.println("arr[" + index + "] = " + num);
            index++;
        }
    }
}

数组操作示例

java
public class ArrayOperations {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        // 求最大值
        int max = arr[0];
        for (int i = 1; i < arr.length; i++) {
            if (arr[i] > max) {
                max = arr[i];
            }
        }
        System.out.println("最大值: " + max);
        
        // 求最小值
        int min = arr[0];
        for (int num : arr) {
            if (num < min) {
                min = num;
            }
        }
        System.out.println("最小值: " + min);
        
        // 求和与平均值
        int sum = 0;
        for (int num : arr) {
            sum += num;
        }
        double avg = (double) sum / arr.length;
        System.out.println("总和: " + sum);
        System.out.println("平均值: " + avg);
        
        // 查找元素
        int target = 25;
        int index = -1;
        for (int i = 0; i < arr.length; i++) {
            if (arr[i] == target) {
                index = i;
                break;
            }
        }
        System.out.println("元素 " + target + " 的索引: " + index);
        
        // 统计元素出现次数
        int[] counts = {1, 2, 3, 2, 1, 2, 3, 3, 3};
        int targetNum = 3;
        int count = 0;
        for (int num : counts) {
            if (num == targetNum) {
                count++;
            }
        }
        System.out.println(targetNum + " 出现的次数: " + count);
    }
}

数组排序

java
import java.util.Arrays;

public class ArraySort {
    public static void main(String[] args) {
        int[] arr = {64, 34, 25, 12, 22, 11, 90};
        
        // 使用 Arrays.sort() 排序
        System.out.println("排序前: " + Arrays.toString(arr));
        Arrays.sort(arr);
        System.out.println("排序后: " + Arrays.toString(arr));
        
        // 冒泡排序(手动实现)
        int[] arr2 = {64, 34, 25, 12, 22, 11, 90};
        System.out.println("\n冒泡排序:");
        for (int i = 0; i < arr2.length - 1; i++) {
            for (int j = 0; j < arr2.length - 1 - i; j++) {
                if (arr2[j] > arr2[j + 1]) {
                    // 交换元素
                    int temp = arr2[j];
                    arr2[j] = arr2[j + 1];
                    arr2[j + 1] = temp;
                }
            }
        }
        System.out.println("排序后: " + Arrays.toString(arr2));
        
        // 选择排序
        int[] arr3 = {64, 34, 25, 12, 22, 11, 90};
        System.out.println("\n选择排序:");
        for (int i = 0; i < arr3.length - 1; i++) {
            int minIndex = i;
            for (int j = i + 1; j < arr3.length; j++) {
                if (arr3[j] < arr3[minIndex]) {
                    minIndex = j;
                }
            }
            // 交换
            int temp = arr3[i];
            arr3[i] = arr3[minIndex];
            arr3[minIndex] = temp;
        }
        System.out.println("排序后: " + Arrays.toString(arr3));
    }
}

多维数组

二维数组

二维数组可以看作是一维数组的数组,常用于表示矩阵或表格数据。

java
public class TwoDimensionalArray {
    public static void main(String[] args) {
        // 声明和初始化
        // 方式一:先声明后初始化
        int[][] matrix1;
        matrix1 = new int[3][4];  // 3行4列
        
        // 方式二:声明时初始化
        int[][] matrix2 = new int[3][4];
        
        // 方式三:静态初始化
        int[][] matrix3 = {
            {1, 2, 3},
            {4, 5, 6},
            {7, 8, 9}
        };
        
        // 访问元素
        System.out.println("matrix3[0][0] = " + matrix3[0][0]);  // 1
        System.out.println("matrix3[1][2] = " + matrix3[1][2]);  // 6
        
        // 获取行数和列数
        System.out.println("行数: " + matrix3.length);           // 3
        System.out.println("第0行列数: " + matrix3[0].length);   // 3
        
        // 遍历二维数组
        System.out.println("\n遍历二维数组:");
        for (int i = 0; i < matrix3.length; i++) {
            for (int j = 0; j < matrix3[i].length; j++) {
                System.out.print(matrix3[i][j] + " ");
            }
            System.out.println();
        }
        
        // 使用增强 for 循环遍历
        System.out.println("\n增强 for 循环遍历:");
        for (int[] row : matrix3) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

不规则二维数组

java
public class IrregularArray {
    public static void main(String[] args) {
        // 不规则数组:每行的列数可以不同
        int[][] irregular = new int[3][];
        
        // 为每行分配不同的列数
        irregular[0] = new int[2];  // 第0行有2列
        irregular[1] = new int[3];  // 第1行有3列
        irregular[2] = new int[4];  // 第2行有4列
        
        // 初始化
        int value = 1;
        for (int i = 0; i < irregular.length; i++) {
            for (int j = 0; j < irregular[i].length; j++) {
                irregular[i][j] = value++;
            }
        }
        
        // 打印
        System.out.println("不规则二维数组:");
        for (int[] row : irregular) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
        
        // 使用静态初始化创建不规则数组
        int[][] triangle = {
            {1},
            {2, 3},
            {4, 5, 6},
            {7, 8, 9, 10}
        };
        
        System.out.println("\n三角形数组:");
        for (int[] row : triangle) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

二维数组应用

java
public class TwoDArrayApplications {
    public static void main(String[] args) {
        // 矩阵加法
        int[][] a = {
            {1, 2, 3},
            {4, 5, 6}
        };
        int[][] b = {
            {7, 8, 9},
            {10, 11, 12}
        };
        
        int[][] sum = new int[2][3];
        for (int i = 0; i < a.length; i++) {
            for (int j = 0; j < a[i].length; j++) {
                sum[i][j] = a[i][j] + b[i][j];
            }
        }
        
        System.out.println("矩阵加法结果:");
        printMatrix(sum);
        
        // 矩阵转置
        int[][] original = {
            {1, 2, 3},
            {4, 5, 6}
        };
        
        int rows = original.length;
        int cols = original[0].length;
        int[][] transposed = new int[cols][rows];
        
        for (int i = 0; i < rows; i++) {
            for (int j = 0; j < cols; j++) {
                transposed[j][i] = original[i][j];
            }
        }
        
        System.out.println("\n矩阵转置:");
        System.out.println("原矩阵:");
        printMatrix(original);
        System.out.println("转置后:");
        printMatrix(transposed);
        
        // 杨辉三角
        System.out.println("\n杨辉三角(10行):");
        int[][] yanghui = new int[10][];
        for (int i = 0; i < yanghui.length; i++) {
            yanghui[i] = new int[i + 1];
            yanghui[i][0] = 1;  // 每行第一个元素
            yanghui[i][i] = 1;  // 每行最后一个元素
            
            // 计算中间元素
            for (int j = 1; j < i; j++) {
                yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
            }
        }
        
        // 打印杨辉三角
        for (int[] row : yanghui) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
    
    // 打印矩阵
    public static void printMatrix(int[][] matrix) {
        for (int[] row : matrix) {
            for (int num : row) {
                System.out.print(num + " ");
            }
            System.out.println();
        }
    }
}

Arrays 工具类

java.util.Arrays 类提供了很多操作数组的方法。

java
import java.util.Arrays;

public class ArraysClass {
    public static void main(String[] args) {
        int[] arr = {3, 1, 4, 1, 5, 9, 2, 6};
        
        // 1. toString():数组转字符串
        System.out.println("toString: " + Arrays.toString(arr));
        
        // 2. sort():排序
        int[] arr2 = arr.clone();
        Arrays.sort(arr2);
        System.out.println("sort: " + Arrays.toString(arr2));
        
        // 3. binarySearch():二分查找(数组必须有序)
        int index = Arrays.binarySearch(arr2, 5);
        System.out.println("5 的索引: " + index);
        
        // 4. fill():填充数组
        int[] filled = new int[5];
        Arrays.fill(filled, 100);
        System.out.println("fill: " + Arrays.toString(filled));
        
        // 部分填充
        int[] partial = new int[10];
        Arrays.fill(partial, 2, 7, 50);  // 索引2到6填充50
        System.out.println("部分填充: " + Arrays.toString(partial));
        
        // 5. copyOf():复制数组
        int[] copied = Arrays.copyOf(arr, 5);  // 复制前5个元素
        System.out.println("copyOf(5): " + Arrays.toString(copied));
        
        int[] expanded = Arrays.copyOf(arr, 15);  // 扩展长度
        System.out.println("copyOf(15): " + Arrays.toString(expanded));
        
        // 6. copyOfRange():范围复制
        int[] range = Arrays.copyOfRange(arr, 2, 6);  // 复制索引2到5
        System.out.println("copyOfRange(2,6): " + Arrays.toString(range));
        
        // 7. equals():比较数组内容
        int[] a1 = {1, 2, 3};
        int[] a2 = {1, 2, 3};
        int[] a3 = {1, 2, 4};
        System.out.println("a1 == a2: " + (a1 == a2));            // false
        System.out.println("equals(a1, a2): " + Arrays.equals(a1, a2));  // true
        System.out.println("equals(a1, a3): " + Arrays.equals(a1, a3));  // false
        
        // 8. 二维数组操作
        int[][] matrix1 = {{1, 2}, {3, 4}};
        int[][] matrix2 = {{1, 2}, {3, 4}};
        System.out.println("deepToString: " + Arrays.deepToString(matrix1));
        System.out.println("deepEquals: " + Arrays.deepEquals(matrix1, matrix2));
    }
}

数组常见问题

数组越界

java
public class ArrayIndexOutOfBounds {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5};
        
        // 正确访问
        System.out.println("arr[0] = " + arr[0]);
        System.out.println("arr[4] = " + arr[4]);
        
        // 数组越界(运行时错误)
        try {
            System.out.println(arr[5]);  // ArrayIndexOutOfBoundsException
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("数组越界异常: " + e.getMessage());
        }
        
        try {
            System.out.println(arr[-1]);  // 负数索引
        } catch (ArrayIndexOutOfBoundsException e) {
            System.out.println("负数索引异常: " + e.getMessage());
        }
        
        // 安全访问方式
        int index = 5;
        if (index >= 0 && index < arr.length) {
            System.out.println(arr[index]);
        } else {
            System.out.println("索引 " + index + " 超出范围");
        }
    }
}

空指针异常

java
public class NullPointerArray {
    public static void main(String[] args) {
        int[] arr = null;
        
        // 空指针异常
        try {
            System.out.println(arr.length);  // NullPointerException
        } catch (NullPointerException e) {
            System.out.println("空指针异常: 数组为 null");
        }
        
        // 安全访问方式
        if (arr != null) {
            System.out.println(arr.length);
        } else {
            System.out.println("数组为 null");
        }
    }
}

数组复制

java
public class ArrayCopy {
    public static void main(String[] args) {
        int[] original = {1, 2, 3, 4, 5};
        
        // 方式一:循环复制
        int[] copy1 = new int[original.length];
        for (int i = 0; i < original.length; i++) {
            copy1[i] = original[i];
        }
        
        // 方式二:clone()
        int[] copy2 = original.clone();
        
        // 方式三:Arrays.copyOf()
        int[] copy3 = Arrays.copyOf(original, original.length);
        
        // 方式四:System.arraycopy()
        int[] copy4 = new int[original.length];
        System.arraycopy(original, 0, copy4, 0, original.length);
        
        // 验证:修改原数组不影响副本
        original[0] = 100;
        System.out.println("原数组: " + Arrays.toString(original));
        System.out.println("副本1: " + Arrays.toString(copy1));
        
        // 浅拷贝问题(引用类型数组)
        Person[] persons = {new Person("张三"), new Person("李四")};
        Person[] personsCopy = persons.clone();
        
        // 修改对象属性会影响副本
        persons[0].name = "王五";
        System.out.println("\n原数组: " + persons[0].name);      // 王五
        System.out.println("副本: " + personsCopy[0].name);      // 王五(也变了)
    }
}

class Person {
    String name;
    public Person(String name) {
        this.name = name;
    }
}

数组与算法

二分查找

java
import java.util.Arrays;

public class BinarySearch {
    public static void main(String[] args) {
        int[] arr = {1, 3, 5, 7, 9, 11, 13, 15, 17, 19};
        
        int target = 7;
        int index = binarySearch(arr, target);
        System.out.println("查找 " + target + ",索引: " + index);
        
        target = 8;
        index = binarySearch(arr, target);
        System.out.println("查找 " + target + ",索引: " + index);  // -1(未找到)
    }
    
    /**
     * 二分查找(非递归)
     * @param arr 有序数组
     * @param target 目标值
     * @return 索引,未找到返回 -1
     */
    public static int binarySearch(int[] arr, int target) {
        int left = 0;
        int right = arr.length - 1;
        
        while (left <= right) {
            int mid = left + (right - left) / 2;  // 防止溢出
            
            if (arr[mid] == target) {
                return mid;
            } else if (arr[mid] < target) {
                left = mid + 1;
            } else {
                right = mid - 1;
            }
        }
        
        return -1;  // 未找到
    }
}

数组反转

java
import java.util.Arrays;

public class ArrayReverse {
    public static void main(String[] args) {
        int[] arr = {1, 2, 3, 4, 5, 6};
        System.out.println("原数组: " + Arrays.toString(arr));
        
        // 方式一:双指针
        int[] arr1 = arr.clone();
        int left = 0, right = arr1.length - 1;
        while (left < right) {
            int temp = arr1[left];
            arr1[left] = arr1[right];
            arr1[right] = temp;
            left++;
            right--;
        }
        System.out.println("反转后: " + Arrays.toString(arr1));
        
        // 方式二:新建数组
        int[] arr2 = arr.clone();
        int[] reversed = new int[arr2.length];
        for (int i = 0; i < arr2.length; i++) {
            reversed[i] = arr2[arr2.length - 1 - i];
        }
        System.out.println("新数组反转: " + Arrays.toString(reversed));
    }
}

小结

本章我们学习了:

  • 一维数组:声明、初始化、遍历、操作
  • 二维数组:规则数组和不规则数组
  • Arrays 工具类:排序、查找、复制、填充等
  • 数组常见问题:越界、空指针、浅拷贝
  • 数组算法:排序、查找、反转

下一章,我们将学习 面向对象基础,了解 Java 面向对象编程的核心概念。