当前位置: 首页 > news >正文

Java基础(六):数组全面解析

Java基础系列文章

Java基础(一):初识Java——发展历程、技术体系与JDK环境搭建

Java基础(二):八种基本数据类型详解

Java基础(三):逻辑运算符详解

Java基础(四):位运算符详解

Java基础(五):流程控制全解析——分支(if/switch)和循环(for/while)的深度指南

Java基础(六):数组全面解析

目录

  • 一、数组的概述
    • 1、什么是数组?
    • 2、数组的特点
    • 3、数组分类
  • 二、一维数组
    • 1、声明数组
    • 2、分配内存空间
    • 3、声明 + 初始化
    • 4、静态初始化(声明时直接赋值)
    • 5、动态初始化(先分配长度,后赋值)
    • 6、内存结构分析
    • 7、数组下标为什么从0开始?
  • 三、多维数组(二维数组)
    • 1、固定大小的二维数组
    • 2、静态初始化(直接赋值)
    • 3、动态初始化(每行不同长度 - 不规则数组)
    • 4、遍历二维数组
    • 5、内存结构分析
  • 四、java.util.Arrays工具类详解
    • 1、数组转字符串
    • 2、数组转集合
    • 3、数组排序
    • 4、二分查找
    • 5、数组比较
    • 6、数组填充
    • 7、数组复制
    • 8、流与并行操作(Java 8+)

一、数组的概述

1、什么是数组?

  在 Java 中,数组(Array)是一种容器,用于存储固定大小同一种数据类型的多个元素。
数组在内存中是连续存储的,每个元素通过索引(从 0 开始)来访问。

在这里插入图片描述

2、数组的特点

  • 固定长度:数组长度在创建时确定,不可动态改变
  • 同类型元素:所有元素必须是相同数据类型(基本类型或引用类型
  • 连续内存分配:元素在内存中连续存储,支持高效随机访问
  • 索引访问:通过索引(从0开始)访问元素,如arr[0]
  • 数组是对象继承自Object类,可用Object类方法(如toString()),有length属性,而不是方法
  • 默认值初始化:创建时自动初始化默认值(如int为0,boolean为false,引用为null)

3、数组分类

按元素类型分类

类型示例特点
基本类型数组int[], char[], double[]存储基本数据类型值
对象引用数组String[], Object[], User[]存储对象引用(内存地址)

按维度分类

类型声明方式示例特点
一维数组(常用)数据类型[] 变量名int[] arr = new int[3];线性结构,单行元素
二维数组数据类型[][] 变量名int[][] matrix = new int[2][3];表格结构(数组的数组)
多维数组数据类型[][][]...int[][][] cube = new int[3][3][3];更高维度的数据(如三维空间)

二、一维数组

1、声明数组

// 推荐声明方式(类型与[]结合)
int[] numbers;  // 合法但不推荐(C语言风格)
int numbers[];  

可以替换 int 为任意基本数据类型(如 double, char, boolean)或引用类型(如 String, Student)

2、分配内存空间

numbers = new int[5];  // 创建一个长度为 5 的整型数组,默认值为 0

3、声明 + 初始化

int[] numbers = new int[5]; // 所有元素默认初始化为 0

4、静态初始化(声明时直接赋值)

// 标准格式
String[] names = new String[]{"Alice", "Bob", "Charlie"};
//或
String[] names;
names = new String[]{"Alice", "Bob", "Charlie"};// 简写格式(自动推断长度)
int[] primes = {2, 3, 5, 7, 11}; 

5、动态初始化(先分配长度,后赋值)

int[] arr = new int[3];  // 分配5个int的内存(默认值: [0, 0, 0])
arr[0] = 10;             // 通过索引赋值

错误写法:int[] arr = new int[5]{1,2,3,4,5}; //错误的,后面有{}指定元素列表,就不能在[]中指定元素个数了

6、内存结构分析

  1. 声明引用变量
    • int[] arr; 在中创建引用变量 arr,初始值为 null(未指向任何对象)
  2. 实例化数组对象
    • arr = new int[3]; 在中开辟连续内存空间
    • 分配空间 = 24字节(对象头) + 元素占用空间(如 int[3] 为 24 + 3×4 = 36字节)
    • 元素按索引依次紧密排列(如地址 0x001 存 arr[0],0x005 存 arr[1],偏移量由元素类型决定)
  3. 地址赋值
    • 堆中数组的首地址被赋给栈中的引用变量 arr(如输出 arr 显示 [I@5f150435,[表示一维数组,I表示int类型,@后为地址的哈希值
  4. 内存示例分析
    int[] arr = new int[3];  // 栈中arr保存堆地址0x001
    arr[0] = 5;              // 堆中0x001地址存入5
    int[] arr2 = arr;        // arr2复制arr的地址(指向同一堆对象)
    arr2[1] = 9;             // 修改影响arr[1](因共享堆内存)
    
    • 结果:arr[1] 输出 9,因 arr 和 arr2 指向同一堆对象

7、数组下标为什么从0开始?

  1. 物理内存的连续性
    • 数组在内存中以连续地址存储,首地址是第一个元素的起始位置
    • 元素地址计算公式为:元素地址 = 首地址 + 下标 × 数据类型字节大小
    • 例如:int[](4字节)的首地址为1000时:
      • a[0]地址 = 1000 + 0×4 = 1000
      • a[1]地址 = 1000 + 1×4 = 1004
      • 若下标从1开始,公式需改为:首地址 + (下标-1)×字节大小出一次减法运算
  2. 减少CPU指令开销
    • 加减法运算在CPU中属于基础指令但仍有耗时
    • 数组访问是高频操作,从0开始可避免额外的i-1计算,提升寻址效率

三、多维数组(二维数组)

  二维数组可以看成是数组的数组,也可以理解为一个矩阵结构。每个元素都是一个一维数组

1、固定大小的二维数组

int[][] matrix = new int[2][3]; // 两行三列,元素默认值为 0

这相当于:

[[0, 0, 0],[0, 0, 0]
]

2、静态初始化(直接赋值)

// 标准版
int[][] matrix1 = new int[][]{{1, 2, 3},{4, 5, 6}
};// 或者简写版
int[][] matrix = new int [][]{{1, 2, 3},{4, 5, 6}
};

3、动态初始化(每行不同长度 - 不规则数组)

int[][] jagged = new int[3][];
jagged[0] = new int[2];   // 第一行 2 个元素
jagged[1] = new int[4];   // 第二行 4 个元素
jagged[2] = new int[3];   // 第三行 3 个元素

注:int[][]arr = new int[][3]; //错误写法

4、遍历二维数组

  • 使用嵌套 for 循环
for (int i = 0; i < matrix.length; i++) {               // 遍历行for (int j = 0; j < matrix[i].length; j++) {        // 遍历列System.out.print(matrix[i][j] + " ");}System.out.println(); // 换行
}
  • 使用增强 for-each 循环
for (int[] row : matrix) {for (int value : row) {System.out.print(value + " ");}System.out.println();
}

5、内存结构分析

  1. 外层数组(行数组)
    • 存储对每个内层一维数组的引用(指针)
    • 内存连续:外层数组本身是连续存储
    • 示例:int[][] arr = new int[3][4] 会创建一个长度为 3 的数组(每个元素是 int[] 类型)
  2. 内层数组(列数组)
    • 存储实际数据
    • 内存连续:每个内层数组在堆中是独立分配的连续内存块
    • 不同内层数组之间内存地址不连续(可能分散在堆中)
int[][] arr = new int[3][4];

内存结构示意图:

栈 (Stack)
┌──────┐
| arr  │ → 指向堆中的外层数组
└──────┘堆 (Heap)
外层数组 (连续)       内层数组 (独立连续块)
┌──────────┐       ┌───────────┐
│ arr[0]   │ ─────→│ [0][0] = 0│
├──────────┤       │ [0][1] = 0│
│ arr[1]   │ ──┐   │ [0][2] = 0│
├──────────┤   │   │ [0][3] = 0│
│ arr[2]   │ ──┼──→└───────────┘
└──────────┘   ││   ┌───────────┐└──→│ [1][0] = 0││ [1][1] = 0││ [1][2] = 0││ [1][3] = 0│└───────────┘┌───────────┐│ [2][0] = 0││ [2][1] = 0││ [2][2] = 0││ [2][3] = 0│└───────────┘

四、java.util.Arrays工具类详解

1、数组转字符串

  • toString():一维数组的可读字符串
    int[] arr = {1, 2, 3};
    System.out.println(Arrays.toString(arr)); // 输出:[1, 2, 3]
    
  • deepToString():支持多维数组
    int[][] matrix = {{1, 2}, {3, 4}};
    System.out.println(Arrays.deepToString(matrix)); // 输出:[[1, 2], [3, 4]]
    

2、数组转集合

  • asList() :将数组转为固定大小的List(不可增删,可修改元素
    String [] array = {"A","B","C"}
    List<String> list = Arrays.asList(array);
    list.set(0, "X"); // 允许修改
    // list.add("D"); // 错误!UnsupportedOperationException// 使用 ArrayList 构造函数,解决不能增删除的问题
    List<String> list = new ArrayList<>(Arrays.asList(array));
    

3、数组排序

  • 基本类型数组:使用双轴快速排序
    int[] arr = {5, 2, 9, 1};
    Arrays.sort(arr); // 结果:[1, 2, 5, 9]
    
  • 对象数组:使用归并排序(稳定排序),需实现 Comparable 接口
    String[] names = {"John", "Alice", "Bob"};
    Arrays.sort(names); // 结果:["Alice", "Bob", "John"]
    
  • 自定义排序:通过 Comparator 指定规则
    Arrays.sort(names, (a, b) -> b.compareTo(a)); // 逆序:["John", "Bob", "Alice"]
    
  • 指定范围排序:左闭右开
    int[] arr = {5, 9, 1, 3};
    Arrays.sort(arr, 1, 3); // 对索引 [1, 3) 区间排序,结果:[5, 1, 9, 3]
    

4、二分查找

  • binarySearch():找到返回索引;未找到返回 -(插入点) - 1,前提必须已排序
    int[] sorted = {1, 3, 5, 7};
    int index1 = Arrays.binarySearch(sorted, 5); // 返回 2(找到)
    int index2 = Arrays.binarySearch(sorted, 4); // 返回 -3(未找到,插入点为 2)
    

5、数组比较

  • equals() :比较两个数组内容是否相等(长度和对应元素相同
    int[] a = {1, 2};
    int[] b = {1, 2};
    boolean isEqual = Arrays.equals(a, b); // true
    
  • deepEquals():用于多维数组的深度比较
    int[][] matrix1 = {{1, 2}, {3, 4}};
    int[][] matrix2 = {{1, 2}, {3, 4}};
    boolean deepEqual = Arrays.deepEquals(matrix1, matrix2); // true
    

6、数组填充

  • fill():将数组所有元素(或指定范围)设为指定值
    int[] arr = new int[3];
    Arrays.fill(arr, 10);      // [10, 10, 10]
    Arrays.fill(arr, 1, 3, 5); // [10, 5, 5](索引 [1,3) 还是左闭右开)
    

7、数组复制

  • copyOf():复制指定长度
    int[] original = {1, 2, 3};
    int[] copy = Arrays.copyOf(original, 2); // [1, 2](截断)
    int[] extended = Arrays.copyOf(original, 5); // [1, 2, 3, 0, 0](填充默认值)
    
  • copyOfRange():复制指定范围,还是左闭右开
    int[] rangeCopy = Arrays.copyOfRange(original, 1, 3); // [2, 3](索引 [1,3))
    

8、流与并行操作(Java 8+)

  • parallelSort():利用多核处理器并行排序,适合大数据量(大于10000 时性能优势明显)
    int[] largeArray = ...;
    Arrays.parallelSort(largeArray);
    
  • stream(T[] array):将数组转换为流(Stream),可配合流式操作
    int[] arr = {1, 2, 3};
    IntStream stream = Arrays.stream(arr);
    stream.forEach(System.out::println);// 数组转流并操作内部数据
    long count = Arrays.stream(new int[]{1, 2, 3}).filter(x -> x > 1).count(); // 2// 也可以实现数组转集合
    int[] array = {1, 2, 3};
    List<Integer> list = Arrays.stream(array) // IntStream.boxed()       // 装箱为 Integer.collect(Collectors.toList());
    
http://www.dtcms.com/a/262863.html

相关文章:

  • RF100:多领域目标检测基准数据集(猫脸码客第284期)
  • 【时时三省】vectorcast使用教程
  • PIXHAWK(ardupilot4.52)上传航点的bug
  • Java-day30-多线程02
  • 大模型——怎么让 AI 写出好看有设计感的网页
  • 链表题解——移除链表元素【LeetCode】
  • 中国电子学会等级考试Python编程真题+答案+解析
  • Spring 依赖注入:官方推荐方式及最佳实践
  • MySQL索引失效场景分析
  • 数据结构笔记5:环形链表的数理分析
  • mysql 小版本升级实战分享
  • 力扣 hot100 Day30
  • 开疆智能CCLinkIE转Canopen网关连接台达伺服驱动器配置案例
  • 自己电脑搭建本地服务器并实现公网访问,内网也能提供互联网连接使用
  • 七层负载均衡和四层负载均衡
  • 打卡day58
  • 数据库表关系设计详解:一对一、一对多、多对多及自关联
  • ShardingSphere完成MySQL集群部署
  • Vue3静态文档资源展示的实现和使用总结
  • 国产车哪款有远程代驾功能?远程代驾+自动驾驶
  • DDoS攻击及其防护方案
  • 超大js文件多层级引用缓存在网络较差的时候无法调用使用问题
  • Rust C++ OpenCV kafka-rs实践
  • 生成式人工智能实战 | 变分自编码器(Variational Auto-Encoder, VAE)
  • 二刷 苍穹外卖day09
  • macos 安装 xcode
  • 借助 KubeMQ 简化多 LLM 集成
  • 深度学习专栏总结
  • 生信分析之流式数据分析:Flowjo 软件核心功能全解析
  • Openssl升级