【Java】——数组深度解析(从内存原理到高效应用实践)

🎁个人主页:User_芊芊君子

🎉欢迎大家点赞👍评论📝收藏⭐文章

🔍系列专栏:【Java】内容概括


【前言】

在Java编程的世界里,数组是一种基本且强大的数据结构,它能够在一块连续的内存空间中存储多个相同类型的数据元素。无论是开发小型应用,还是构建大型系统,数组都扮演着不可或缺的角色。本文将深入探讨Java数组的定义、初始化、访问以及常见操作,帮助你全面掌握这一重要概念。

文章目录:

  • 一、数组的基本概念
    • [1. 什么是数组](#1. 什么是数组)
    • [2. 数组的创建及初始化](#2. 数组的创建及初始化)
      • [2.1 数组的创建](#2.1 数组的创建)
      • [2.2 数组的初始化](#2.2 数组的初始化)
    • [3. 数组的使用](#3. 数组的使用)
      • [3.1 数组中元素访问](#3.1 数组中元素访问)
      • [3.2 遍历数组](#3.2 遍历数组)
  • 二、数组是引用类型
    • [1. 初始JVM的内存分布](#1. 初始JVM的内存分布)
    • [2. 基本类型变量与引⽤类型变量的区别](#2. 基本类型变量与引⽤类型变量的区别)
    • [3. 引用变量](#3. 引用变量)
    • [4. nall](#4. nall)
  • 三、数组的应用
    • [1. 保存数据](#1. 保存数据)
    • [2. 作为函数的参数](#2. 作为函数的参数)
    • [3. 作为函数返回值](#3. 作为函数返回值)
  • 四、操作数据⼯具类Arrays与数组练习
    • [1. 数组转字符串](#1. 数组转字符串)
    • [2. 数组拷贝](#2. 数组拷贝)
    • [3. 查找数组中的制定元素](#3. 查找数组中的制定元素)
      • [3.1 顺序查找](#3.1 顺序查找)
      • [3.2 二分查找](#3.2 二分查找)
    • [4. 数组排序(冒泡排序)](#4. 数组排序(冒泡排序))
    • [5. 数组逆序](#5. 数组逆序)
  • 五、二维数组
    • 1.基本语法
    • [2. 不规则二维数组](#2. 不规则二维数组)

一、数组的基本概念

1. 什么是数组

数组是一种复合数据类型,它可以看作是一个容器,用于存储多个相同类型的变量。这些变量在内存中按顺序排列,每个变量都有一个唯一的索引,通过索引可以快速访问数组中的元素。在Java中,数组是对象,无论它存储的是基本数据类型还是引用数据类型。

  • 数组中存放的元素类型相同;
  • 数组的空间是连在一起的;
  • 每个空间都有自己的编号,起始位置编号为0,即数组下标

2. 数组的创建及初始化

2.1 数组的创建

java 复制代码
T[] 数组名 = new T[N];
// T:表⽰数组中存放元素的类型
// T[]:表⽰数组的类型
// N:表⽰数组的⻓度
java 复制代码
int[] array1 = new int[10];
float[] array2 = new float[20];
String[] array3 = new String[30];

2.2 数组的初始化

数组的初始化主要分为动态初始化以及静态初始化

  • 动态初始化:在创建一个数组时,直接指定数组元素的个数
java 复制代码
int[] array = new int[10];
  • 静态初始化:在创建数组时不直接指定数据元素个数,⽽直接将具体的数据内容进⾏指定
java 复制代码
int[] array1 = new int[]{0,1,2,3,4,5};
float[] array2 = new float[]{0,1,2,3,4,5};
String[] array3 = new String[]{0,1,2,3,4,5};

【注意】

  • 静态初始化虽然没有指定数组长度,编译器在编译时会根据{}中的元素个数来确定数组的长度;
  • 静态初始化时,{}中数据类型必须与 前数据类型一致;
  • 静态初始化可以简写,省去后面的new T ;
java 复制代码
java int[] array1 = {0,1,2,3,4,5}; 
float[] array2 = {0,1,2,3,4,5};
String[] array3 = {0,1,2,3,4,5};
  • 静态和动态初始化也可以分为两步,但是省略格式不可以
java 复制代码
int[] array;
array = new int[5];
  • 如果没有对数组进⾏初始化,数组中元素有其默认值


如果数组中存储元素类型为引⽤类型,默认值为null

java 复制代码
String name = new String[2];//nall,nall

3. 数组的使用

3.1 数组中元素访问

数组在内存中是⼀段连续的空间,空间的编号都是从0开始的,依次递增,该编号称为数组的下标,数组可以通过下标访问其任意位置的元素。

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = new int[]{12,55,94,66,33};
        System.out.println(array[0]);
        System.out.println(array[1]);
        System.out.println(array[2]);
        System.out.println(array[3]);
        System.out.println(array[4]);
    }
}

下标的访问不能越界

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = new int[5];
        System.out.println(array[6]);//越界了
    }
}

3.2 遍历数组

遍历数组就是将数组中的所有元素都访问一遍,访问是对所有元素进行某种操作,eg: 打印

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = new int[]{10,20,30,40,50};
        System.out.println(array[0]);
        System.out.println(array[1]);
        System.out.println(array[2]);
        System.out.println(array[3]);
        System.out.println(array[4]);
  • 这样写,修改起来就比较麻烦,我们可以用循环来进行打印
java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = new int[]{10,20,30,40,50};
//        System.out.println(array[0]);
//        System.out.println(array[1]);
//        System.out.println(array[2]);
//        System.out.println(array[3]);
//        System.out.println(array[4]);
        for (int i = 0; i < 5; i++) {
            System.out.println(array[i]);
        }
    }
}
  • 在数组中可以通过 数组对象.length 来获取数组的⻓度
java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = new int[]{10,20,30,40,50};
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i]);
        }
    }
}
  • for-each 是 for 循环的另外⼀种使⽤⽅式. 能够更⽅便的完成对数组的遍历. 取得数组的每个元素,并放到x中可以避免循环条件和更新语句写错.
java 复制代码
    int[] array = {1,2,3};
    for(int x : array){
        System.out.println(x);
        }

二、数组是引用类型

1. 初始JVM的内存分布

  • 程序计数器 (PC Register): 只是⼀个很⼩的空间, 保存下⼀条执⾏的指令的地址
  • 虚拟机栈(JVM Stack): 与⽅法调⽤相关的⼀些信息,每个⽅法在执⾏时,都会先创建⼀个栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的⼀些信息,保存的都是与⽅法执⾏时相关的⼀些信息。⽐如:局部变量。当⽅法运⾏结束后,栈帧就被销毁了,即栈帧中保存 的数据也被销毁了。
  • 本地⽅法栈(NativeMethod Stack): 本地⽅法栈与虚拟机栈的作⽤类似. 只不过保存的内容是Native⽅法的局部变量. 在有些版本的 JVM实现中(例如HotSpot), 本地⽅法栈和虚拟机栈是⼀起的
  • (Heap): JVM所管理的最⼤内存区域. 使⽤ ==new创建的对象都是在堆上保存 ==(例如前⾯的 new int\[\]{1, 2, 3} ),堆是随着程序开始运⾏时⽽创建,随着程序的退出⽽销毁,堆中的数据只 要还有在使⽤,就不会被销毁。
  • ⽅法区(Method Area): ⽤于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后 的代码等数据. ⽅法编译出的的字节码就是保存在这个区域

2. 基本类型变量与引⽤类型变量的区别

  • 基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
  • ⽽引⽤数据类型创建的变量,⼀般称为对象的引⽤,其空间中存储的是对象所在空间的地址。
java 复制代码
public class Test {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int[] array = {1,2,3};
        int[] array1 = nall;//当一个引用不知道初始化什么的时候,就初始化成nall
    }
}
  • 栈上变量的地址是获取不到的
  • 当一个引用不知道初始化什么的时候,就初始化成nall

3. 引用变量

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array1 = new int [3];
        array1[0] = 10;
        array1[1] = 20;
        array1[2] = 30;

        int[] array2 = new int[]{1,2,3,4,5};
        array2[0] = 100;
        array2[1] = 200;

        array1 = array2;
        array1[2] = 300;
        array2[3] = 400;
        array2[4] = 400;
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }
    }
}


4. nall

null 在 Java 中表⽰ "空引⽤" , 也就是⼀个不指向对象的引⽤.

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = null;
        System.out.println(array.length );
    }
}

null 的作⽤类似于 C 语⾔中的 NULL (空指针), 都是表⽰⼀个⽆效的内存位置. 因此不能对这个内存进⾏任何读写操作.⼀旦尝试读写, 就会抛NullPointerException. 空指针异常

三、数组的应用

1. 保存数据

这里就不多做解释了

2. 作为函数的参数

  • 参数传基本数据类型
    发现在func⽅法中修改形参 x 的值, 不影响实参的 num 值.
java 复制代码
public class Test {
    public static void main(String[] args) {
        int num = 100;
        ch(num);
        System.out.println("num = " + num);
    }
    public static void ch(int x){
        x = 0;
        System.out.println("x=" + x);
    }
}
  • 参数传数组类型(引⽤数据类型)
    在func⽅法内部修改数组的内容, ⽅法外部的数组内容也发⽣改变.
java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] arr = {1,2,3};
        func(arr);
        System.out.println("arr[0] = "+ arr[0]);
    }
    public static void func(int[] a){
        a[0] = 10;
        System.out.println("a[0] = "+ a[0]);
    }
}


因为数组是引⽤类型,按照引⽤类型来进⾏传递,是可以修改其中存放的内容的。

【总结】

所谓的 "引⽤" 本质上只是存了⼀个地址. Java 将数组设定成引⽤类型, 这样的话后续进⾏数组参数传参,

其实只是将数组的地址传⼊到函数形参中. 这样可以避免对整个数组的拷⻉

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        test1(array);
        printArray(array);
    }

    public static void printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i] + " ");
        }
        System.out.println();
    }
    public static void test1(int[] array){
        array[0] = 99;
    }
}
java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        test2(array);
        printArray(array);
    }

    public static void printArray(int[] array) {
        for (int i = 0; i < array.length; i++) {
            System.out.println(array[i] + " ");
        }
        System.out.println();
    }
    public static void test2(int[] array){
        array = new int[]{100, 200, 300, 400, 500};
    }
}

3. 作为函数返回值

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = fun();
        String str = Arrays.toString(array);
        System.out.println(str);
    }
    public static int[] fun(){
        int a = 1;
        int b = 2;
        int[] ret = new int[]{a,b};
        return ret;
    }
}

四、操作数据⼯具类Arrays与数组练习

1. 数组转字符串

Java 中提供了java.util.Arrays包, 其中包含了⼀些操作数组的常⽤⽅法.使⽤这个⽅法后续打印数组就更⽅便⼀些.

java 复制代码
import java.util.Arrays;
public class Test {
    public static void main(String[] args) {
        int[] arr ={1,2,3,4,5,6};
        String newArr = Arrays.toString(arr);
        System.out.println(newArr);

    }
//    public static String myToString(int[] array){
//        String ret = "[";
//        for (int i = 0; i < array.length; i++) {
//            ret += array[i];
//            if(i != array.length-1){
//                ret +=",";
//            }
//        }
//        ret += "]";
//        return ret;
//    }
}

2. 数组拷贝

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array1 = {1,2,3,4,5};
        int[] array2 = new int[array1.length];
        System.out.println("拷贝前:");
        System.out.println("array1:"+Arrays.toString(array1));
        System.out.println("array2:"+Arrays.toString(array2));

        for (int i = 0; i < array1.length; i++) {
            array2[i] = array1[i];
        }
        System.out.println("拷贝后:");
        System.out.println("array1:"+Arrays.toString(array1));
        System.out.println("array2:"+Arrays.toString(array2));
    }
}

3. 查找数组中的制定元素

3.1 顺序查找

给定⼀个数组, 再给定⼀个元素, 找出该元素在数组中的位置.

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array1 = {1,2,3,4,5};
        int ret = find(array1,4);
        if(ret == -1){
            System.out.println("找不到");
        }
        System.out.println(ret);
    }
    public static int find(int[] array1,int key){
        for (int i = 0; i < array1.length; i++) {
            if(array1[i] == key){
                return i;
            }
        }
        return -1;
    }
}

3.2 二分查找

针对有序数组, 可以使⽤更⾼效的⼆分查找.

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {1, 2, 3, 4, 5};
        int ret = find(array, 3);
        if (ret == -1) {
            System.out.println("找不到");
        } else {
            System.out.println(ret);
        }
    }
    public static int find(int[] array,int key){
        int i = 0;
        int j = array.length-1;
        while(i <= j){
            int mid = (i+j)/2;
            if(array[mid] < key){
                i = mid + 1;
            }else if(array[mid] > key){
                i = mid - 1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

4. 数组排序(冒泡排序)

给定⼀个数组, 让数组升序 (降序) 排序.

假设排升序:

  1. 将数组中相邻元素从前往后依次进⾏⽐较,如果前⼀个元素⽐后⼀个元素⼤,则交换,⼀趟下来后最⼤元素就在数组的末尾
  2. 依次从上上述过程,直到数组中所有的元素都排列好
java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {3,5,23,7,9,33,42,12};
        bubbleSort(array);
        System.out.println("排序后:"+Arrays.toString(array));
    }
    public static void bubbleSort(int[] array){
        for (int i = 0; i < array.length-1; i++) {
            for(int j = 0;j < array.length-1;j++){
                if(array[j] > array[j+1]){
                    int tmp = array[j];
                    array[j] = array[j+1];
                    array[j+1] = tmp;
                }
            }
        }
    }
}

Java中内置了更高效的排序算法

java 复制代码
public static void main(String[] args) {
      int[] arr = {9, 5, 2, 7};
      Arrays.sort(arr);
      System.out.println(Arrays.toString(arr));
}

5. 数组逆序

给定⼀个数组, 将⾥⾯的元素逆序排列.

  • 设定两个下标, 分别指向第⼀个元素和最后⼀个元素.
  • 交换两个位置的元素. 然后让前⼀个下标⾃增, 后⼀个下标⾃减, 循环继续即可.
java 复制代码
public class Test {
    public static void main(String[] args) {
        int[] array = {1,2,3,5,6,9};
        reverse(array);
        System.out.println(Arrays.toString(array));
    }
    public static void reverse(int[] array){
        int i = 0;
        int j = array.length-1;
        while(i <j){
            int tmp = array[i];
            array[i] = array[j];
            array[j] = tmp;
            i++;
            j--;
        }
    }
}

五、二维数组

⼆维数组本质上也就是⼀维数组, 只不过每个元素⼜是⼀个⼀维数组.

1.基本语法

java 复制代码
数据类型[][] 数组名称 = new 数据类型 [⾏数][列数] { 初始化数据 };

列可以省略,行不可以省略

java 复制代码
public class Test {
    public static void main(String[] args) {
        int[][] array = {{1, 2, 3}, {4, 5, 6}};
//        int[][] arr1 = new int[2][3];
//        int[][] arr3 = new int[][]{{1, 2, 3}, {4, 5, 6}};
        for (int i = 0; i < array.length; i++) {
            for (int j = 0; j < array[i].length; j++) {
                System.out.print(array[i][j]+" ");
            }
            System.out.println();
        }
    }
}


  • ⼆维数组是特殊的⼀维数组,⼀维数组的每个元素⼜是⼀个数组
  • arr.length 代表⼆维数组的⾏数
  • arrrow.length 代表⼆维数组的列数

2. 不规则二维数组

不规则的⼆维数组指的是,⼆维数组的列在定义的时候,没有确定。

java 复制代码
int[][] array = new int [2][];
array[0] = new int[3];
array[1] = new int[5];

这就不是⼀个规则的⼆维数组。第1⾏有3列,第2⾏有5列。

【总结】

  • 数组作为Java编程的基础数据结构,掌握其定义和使用方法是迈向高级编程的重要一步。通过本文的介绍,希望你对Java数组有了更深入的理解,并能在实际项目中灵活运用。随着学习的深入,你会发现数组在算法设计、数据处理等领域发挥着更大的作用。
  • 在日常开发中,建议养成良好的编码习惯,合理使用数组,提高程序的性能和可读性。如果你对数组还有其他疑问,欢迎在评论区留言交流。
  • 数组是通往更高级数据结构和算法的基石,祝愿大家在这里是引用 Java编程的道路上越走越远,创造出更优秀的程序!
相关推荐
Scott9999HH6 小时前
【IIoT流量实战】蒸汽管道阀门全关却仍有流量?用 Python 实现涡街信号 FFT 频谱分析与温压全补偿积算网关,深度拆解靠谱的涡街流量计厂家硬核技术标准
开发语言·python
腻害兔6 小时前
【若依项目-产品经理视角】深度拆解 RuoYi-Vue-Pro 商城模块:从商品管理到交易引擎,50 张表撑起一整套电商系统
java·大数据·vue.js·产品经理·ai编程
码智社7 小时前
AES加密原理详解及Java实现加解密实战
java·开发语言
AI云海7 小时前
python 列表、元组、集合和字典
开发语言·python
萧瑟余晖8 小时前
JDK 26 新特性详解
java·开发语言
马优晨9 小时前
Freemarker 完整讲解(后端 Java 模板引擎)
java·开发语言·freemarker·freemarker 完整讲解·freemarker模板引擎
人邮异步社区11 小时前
怎么把C语言学到精通?
c语言·开发语言
心平气和量大福大11 小时前
C#-WPF-控件-TextBox 数据绑定
开发语言·c#·wpf
ttwuai11 小时前
Cursor 生成 CRUD 后,Go 后台接口别只测 200:JWT、RBAC 和 tenant_id 怎么验
开发语言·后端·golang
维天说12 小时前
CLI-Switch 2026年3月版历史设计:Hook、TTY 隔离与 JSON 状态
java·服务器·json