【JAVA】数组的使用

文章目录

  • 前言
  • 一、数组的基本概念
    • [1.1 数组的创建和初始化](#1.1 数组的创建和初始化)
    • [1.2 数组的基本使用](#1.2 数组的基本使用)
  • 二、数组是引用类型
    • [2.1 初始JVM的内存分布](#2.1 初始JVM的内存分布)
    • [2.2 基本类型变量与引用类型变量的区别](#2.2 基本类型变量与引用类型变量的区别)
    • [2.3 再谈引用变量](#2.3 再谈引用变量)
    • [2.4 认识null](#2.4 认识null)
  • 三、数组作为函数的参数和返回值
  • 四、数组的应用场景
    • [4.1 数组转字符串](#4.1 数组转字符串)
    • [4.2 数组的拷贝](#4.2 数组的拷贝)
    • [4.3 深拷贝和浅拷贝问题](#4.3 深拷贝和浅拷贝问题)
    • [4.3 冒泡排序的小优化](#4.3 冒泡排序的小优化)
    • [4.4 数组逆序](#4.4 数组逆序)
    • [4.5 数组逆序](#4.5 数组逆序)
    • [4.6 数组练习](#4.6 数组练习)
  • 五、二维数组
    • [5.1 普通二维数组](#5.1 普通二维数组)
    • [5.2 不规则的二维数组](#5.2 不规则的二维数组)
  • 总结

前言

提示:这里可以添加本文要记录的大概内容:

在Java编程的征途中,数组作为基础却至关重要的数据结构,是每个开发者必须掌握的核心技能。它不仅是存储同类型元素的​​高效容器​​,更是算法实现、数据处理的​​底层基石​​。从简单的成绩管理系统到复杂的矩阵运算,数组以其简洁的内存模型和快速的随机访问能力,奠定了程序逻辑的基本骨架。本篇博客将深入剖析Java数组的特性、应用场景及性能要点,帮助您从语法本质到实战技巧全面驾驭这一编程利器。

注意:和c语言内容大致相同的部分会简单带过或者不讲解


提示:以下是本篇文章正文内容,下面案例可供参考

一、数组的基本概念

1.1 数组的创建和初始化

数组的创建:

java 复制代码
 T[] 数组名 = new T[N];

T:表⽰数组中存放元素的类型

T[]:表⽰数组的类型

N:表⽰数组的⻓度

java 复制代码
public class array {
    public static void main(String[] args) {
        int[] array1=new int[10];
        double[] array2=new double[10];
        String[] array3=new String[10];
    }
}

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

  1. 动态初始化:在创建数组时,直接指定数组中元素的个数,只开辟空间但是不赋初值
  2. 静态初始化:在创建数组时不直接指定数据元素个数,⽽直接将具体的数据内容进⾏指定
    示例代码:
java 复制代码
public class array {
    public static void main(String[] args) {
        int[] array1=new int[]{0,1,2,3,4,5,6};
        double[] array2=new double[]{1.0,2.0,3.0,4.0,5.0,6.0};
        String[] array3=new String[]{"hello"};
        int[] array4={1,2,3,4};
    }
}

【注意事项】:

  • 静态初始化虽然没有指定数组的⻓度,编译器在编译时会根据{}中元素个数来确定数组的⻓度。
  • 静态初始化时,{}中数据类型必须与[]前数据类型⼀致。
  • 静态初始化可以简写,省去后⾯的new T[]。

**

静态和动态初始化也可以分为两步,但是省略格式不可以。

示例代码如下:**

java 复制代码
public class array {
    public static void main(String[] args) {
        int[] array1;
        array1=new int[4];
        int[] array2;
        array2=new int[]{1,2,3};

        //下面方式不可行
        int[] array3;
        array3={1,2,3};
    }
}


如果没有对数组进⾏初始化,数组中元素有其默认值:

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

1.2 数组的基本使用

通过代码来演示数组的使用:

java 复制代码
public class array {
    public static void main(String[] args) {
        String[] array1=new String[]{"hhh","aaa","zzz"};
        array1[2]="dzj";
        for (String str: array1) {
            System.out.println(str);
        }

    }
}

遍历数组:

java 复制代码
public class array {
    public static void main(String[] args) {
        String[] array1=new String[]{"hhh","aaa","zzz"};
        array1[2]="dzj";

        //遍历方式一
        for (String str: array1) {
            System.out.println(str);
        }

        //遍历方式二
        for (int i = 0; i < array1.length; i++) {
            System.out.println(array1[i]);
        }
    }
}

二、数组是引用类型

2.1 初始JVM的内存分布


JVM也对所使用的内存按照功能的不同进行了划分

JVM内存划分(按功能分区)

  1. 程序计数器(PC Register)

    • 占用极小的内存空间
    • 核心功能:保存下一条要执行的指令地址
    • 线程私有,每个线程独立存储
  2. 虚拟机栈(JVM Stack)

    • 存储方法调用相关的运行时数据
    • 方法执行机制:
      • 每个方法执行时创建对应的栈帧
      • 栈帧包含五部分:
      • 局部变量表(方法参数和局部变量)
      • 操作数栈(执行引擎的工作区)
      • 动态链接(指向运行时常量池的方法引用)
      • 返回地址(方法结束后的返回位置)
      • 附加信息(如调试数据)
    • 生命周期:
      • 方法开始执行 → 栈帧入栈
      • 方法执行结束 → 栈帧出栈销毁
  3. 本地方法栈(Native Method Stack)

    • Native方法(本地方法) 提供服务
    • 功能与虚拟机栈类似
    • 特殊说明:在HotSpot等JVM实现中与虚拟机栈合并
  4. 堆(Heap)

    • JVM管理的最主要内存区域(占比最大)

    • 存储特性:
      • 所有new创建的对象 都在堆上分配(包括数组对象)

      java 复制代码
      new int[]{1, 2, 3} // 堆内存分配

      • 对象存储要求:

      • 被引用对象不会被销毁
      • 未被引用对象由GC回收
    • 生命周期管理:
      • JVM启动时创建
      • 程序运行期间动态调整大小
      • JVM退出时销毁

  5. 方法区(Method Area)

    • 核心存储内容:
      已被加载的类元数据 (类名/字段/方法/父类/接口等)
      运行时常量池 (字符串常量等)
      静态变量 (static修饰的类变量)
      即时编译器编译后的代码(JIT优化产物)
    • 特殊说明:字节码指令(编译后的方法代码)存储在此区域

2.2 基本类型变量与引用类型变量的区别

基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值;
⽽引⽤数据类型创建的变量,⼀般称为对象的引⽤,其空间中存储的是对象所在空间的地址。

注意:java中是不能获取到变量的地址的,也就是说java中并没有指针的概念

2.3 再谈引用变量

java 复制代码
public class array {
    public static void main(String[] args) {
        int[] array2 = new int[]{1,2,3,4};
        int[] array1=array2;
        array1[0]=100;
        array1[1]=200;
        array1[2]=300;
        array1[3]=400;
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }
    }
}

注意:这里的array1=array2是地址赋值,所以改变array1中的数组值所以array2中的内容也会发生改变,两个引用变量此时指向了同一块内存空间

2.4 认识null

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

java 复制代码
int[] arr = null;
 System.out.println(arr[0]);
 // 执⾏结果
 
Exception in thread "main" java.lang.NullPointerException
 at Test.main(Test.java:6)


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

JAVA中并没有规定null是零地址

三、数组作为函数的参数和返回值

参数传数组类型(引用数据类型)

java 复制代码
public class array {
    public static void main(String[] args) {
        int[] arr={1,2,3,4,5,6};
        fix(arr);
        for (int x:arr) {
            System.out.println(x);
        }
    }
    public static void fix(int[] arr){
        for (int i = 0; i < arr.length; i++) {
            arr[i]=i*100;
        }
    }
}

总结:所谓的"引用"本质上只是存了⼀个地址.Java将数组设定成引用类型,这样的话后续进行数组参数传参,其实只是将数组的地址传入到函数形参中.这样可以避免对整个数组的拷贝(数组可能⽐较长,那么拷贝开销就会很大).

数组作为函数的返回值
比如:获取斐波那契数列的前N项

java 复制代码
public class array {
    public static void main(String[] args) {
        int[] array=fib(20);
        assert array != null;
        for (int x:array) {
            System.out.println(x);
        }
    }
    public static int[] fib(int n){
       if(n<=0){
           return null;
       }
       int[] array=new int[n];
       array[0]=array[1]=1;
        for (int i = 2; i <array.length ; i++) {
            array[i]=array[i-1]+array[i-2];
        }
        return array;
    }
}

四、数组的应用场景

4.1 数组转字符串

java 复制代码
import java.util.Arrays;
import java.util.Scanner;

public class array {

    public static void main(String[] args) {
        int[] array={1,2,3,4,5,6};
        String ret=Arrays.toString(array);
        System.out.println(ret);
    }
    public static void main1(String[] args) {
        Scanner scanner=new Scanner(System.in);
        int[] array = {2,6,4,1};
        System.out.println(sequence(array));
    }

    public static boolean sequence(int[] array) {
        boolean flag = true;
        int count=0;
        for (int i = 0; i <array.length-3 ; i++) {
            if(array[i]%2!=0){
                count++;
                if(count==3){
                    return true;
                }
            }else{
                count=0;
            }

        }

        return false;
    }
}

4.2 数组的拷贝

java 复制代码
    public static void main(String[] args) {
        int[] array={1,2,3,4,5,6};
        int[] array1=Arrays.copyOf(array,array.length);
        //扩容操作
        int[] array2=Arrays.copyOf(array,array.length*2);
        int[] array3=Arrays.copyOfRange(array,2,5);
        String ret1=Arrays.toString(array1);
        System.out.println(ret1);
        String ret2=Arrays.toString(array2);
        System.out.println(ret2);
        String ret3=Arrays.toString(array3);
        System.out.println(ret3);
    }

注意:数组当中存储的是基本类型数据时,不论怎么拷⻉基本都不会出现什么问题,但如果存储的是引⽤数据类型,拷⻉时需要考虑深浅拷⻉的问题,

源码部分展示:

4.3 深拷贝和浅拷贝问题

深拷贝和浅拷贝通常只出现在引用数据类型的范畴之上,基本数据类型不存在深拷贝和浅拷贝问题!!

当拷贝内容为引用数据类型的时候,浅拷贝指的是拷贝数组的内容仅仅是拷贝变量的值,而没有存储对象本身所存储的内容,而深拷贝恰恰相反。

图片左边是浅拷贝,右边是深拷贝

4.3 冒泡排序的小优化

java 复制代码
    public static void main(String[] args) {
        int[] array={4,6,3,2,1,7,8,11,23,22,42,21};
        bubbleSort(array);
        for (int x: array) {
            System.out.print(x+" ");
        }
    }
    public static void bubbleSort(int[] array){
        for(int i=0;i<array.length-1;i++){
            boolean flg=false;
            for (int j = 0; j < array.length-1-i; j++) {
                if(array[j]>array[j+1]){
                    int tmp=array[j];
                    array[j]=array[j+1];
                    array[j+1]=tmp;
                    flg=true;
                }
            }
            if(!flg){
                return;
            }
        }
    }

冒泡排序本身时间复杂度比较高,使用java内置的sort函数即可:

java 复制代码
public static void main(String[] args) {
        int[] array={4,6,3,2,1,7,8,11,23,22,42,21};
        Arrays.sort(array);
        for (int x: array) {
            System.out.print(x+" ");
        }
    }

4.4 数组逆序

java 复制代码
    public static void main(String[] args) {
        int[] array={1,2,3,4,5,6};
        reverse(array);
        for (int x: array) {
            System.out.print(x+" ");
        }
    }

    public static void reverse(int[] array){
        int left=0;
        int right=array.length-1;
        while(left<right){
            int tmp=array[left];
            array[left]=array[right];
            array[right]=tmp;
            left++;
            right--;
        }
    }

4.5 数组逆序

调整数组顺序使得奇数位于偶数之前。调整之后,不关心大小顺序。
如数组:[1,2,3,4,5,6]
调整后可能是:[1, 5, 3, 4, 2, 6]

java 复制代码
public static void main(String[] args) {
        int[] array={1,2,3,4,5,6};
        change(array);
        for (int x: array) {
            System.out.print(x+" ");
        }
    }

    public static void change(int[] array){
        int left=0;
        int right=array.length-1;
        while(left<right){
            while(left<right&&array[left]%2!=0){
                left++;
            }
            while(left<right&&array[right]%2==0){
                right--;
            }
            int tmp=array[left];
            array[left]=array[right];
            array[right]=tmp;
        }
    }

4.6 数组练习


异或的特点是:

1、n ^ n = 0;即两个相同的数字异或是0

2、0 ^ n = n;即0和任何数字进行异或,结果就是那个任何数字。

java 复制代码
public static void main(String[] args) {
        int[] array={4,1,2,1,2};
        int num=getNum(array);
        System.out.println(num);
    }
    public static int getNum(int[] array){
        int ret=0;
        for (int i = 0; i < array.length; i++) {
            ret^=array[i];
        }
        return ret;
    }
    public static void main6(String[] args) {
        int[] array={1,2,3,4,5,6};
        change(array);
        for (int x: array) {
            System.out.print(x+" ");
        }
    }

五、二维数组

5.1 普通二维数组

基本语法:

数据类型[][] 数组名称 = new 数据类型 [⾏数][列数]{ 初始化数据 };

注意:二维数组行不可以省略,但是列可以省略

java 复制代码
public static void main(String[] args) {
        int[][] array = new int[3][];
    }

代码示例:

java 复制代码
public static void main(String[] args) {
        int[][] array = {{1,2,3},
                        {4,5,6},
                        {7,8,9}};
        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();
        }
    }

5.2 不规则的二维数组

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

java 复制代码
int[][] array = new int[3][];
java 复制代码
public static void main(String[] args) {
        int[][] array = new int[2][];
        array[0]=new int[3];
        array[1]=new int[5];
        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();
        }
    }


总结

作为Java编程的​​基础支柱​​,数组的价值远超出其简单的语法形式。它不仅提供了数据的高效组织方式,更通过多维数组支持复杂数据建模,借助Arrays工具类实现强大操作能力。尽管集合框架在现代开发中日益普及,但在性能敏感的底层系统、算法实现以及内存优化场景中,数组仍展现着不可替代的优势。真正掌握数组的内存机制、遍历技巧与异常处理,将使您的代码在严谨性和效率上实现质的飞跃------这正是构建健壮程序的关键一步。

相关推荐
饕餮争锋9 分钟前
设计模式笔记_创建型_单例模式
java·笔记·设计模式
teeeeeeemo19 分钟前
Number.toFixed() 与 Math.round() 深度对比解析
开发语言·前端·javascript·笔记
我在北京coding25 分钟前
Uncaught (in promise) TypeError: x.isoWeek is not a function
开发语言·javascript·vue.js
showmethetime27 分钟前
[设计模式]创建型模式-单例模式
开发语言
aiguangyuan37 分钟前
Python元组常用操作方法
python·后端开发
Y1_again_0_again40 分钟前
Java 包装类详解
java·开发语言
武子康1 小时前
Java-52 深入浅出 Tomcat SSL工作原理 性能优化 参数配置 JVM优化
java·jvm·后端·servlet·性能优化·tomcat·ssl
别骂我h1 小时前
容器技术技术入门与Docker环境部署
java·spring cloud·docker
闯闯桑1 小时前
Pyspark中的int
大数据·python·spark·pandas
berryyan1 小时前
Windows 环境下通过 WSL2 成功集成 Claude Code 与 PyCharm 的完整指南
人工智能·python