初识java(八):数组的定义与使用

目录

一:数组的基本概念

1.为什么要使⽤数组

2.什么是数组

3.数组的创建及初始化

数组的创建

数组的初始化

4.数组的基本使⽤

二:数组是引⽤类型

1.初始JVM的内存分布

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

3.再谈引⽤变量

4.认识null

三:数组的应⽤场景

1.保存数据

2.作为函数的参数

3.作为函数的返回值

四:操作数组⼯具类Arrays

1.数组转字符串

2.数组拷⻉

[3.数组排序(冒泡排序)](#3.数组排序(冒泡排序))

五:⼆维数组

1.普通的⼆维数组

2.不规则的⼆维数组


本文章大纲:

本文介绍了Java数组的基本概念和使用方法。主要内容包括:

  1. 数组的定义与作用,用于存储多个相同类型的数据;

  2. 数组的创建和初始化方式,包括动态初始化和静态初始化;

  3. 数组的基本操作,如元素访问、修改和遍历;

  4. 数组的内存分配机制,解释基本类型变量与引用类型变量的区别;

  5. 数组的应用场景,包括作为函数参数和返回值;

  6. 数组工具类Arrays的使用,包括数组转字符串、拷贝和排序;

  7. 二维数组的定义和使用方法。文章通过代码示例详细说明了数组的各种操作,并强调了使用数组时需要注意的问题,如数组越界等。

一:数组的基本概念

1.为什么要使⽤数组

假设现在要存5个学⽣的javaSE考试成绩,并对其进⾏输出,按照之前掌握的知识点,我们会写出如下 代码:

java 复制代码
    public static void main(String[] args) {
        int score1 = 70;
        int score2 = 80;
        int score3 = 85;
        int score4 = 60;
        int score5 = 90;
        System.out.println(score1);
        System.out.println(score2);
        System.out.println(score3);
        System.out.println(score4);
        System.out.println(score5);
    }

上述代码没有任何问题,但不好的是:如果有20名同学成绩呢,需要创建20个变量吗?有100个学⽣ 的成绩那不得要创建100个变量。

仔细观察这些学⽣成绩发现:所有成绩的类型都是相同的,那Java中 存在可以存储多个相同类型的数据吗?这就是本节要讲的数组

2.什么是数组

数组:可以看成是相同类型元素的⼀个集合。在内存中是⼀段连续的空间。⽐如现实中的⻋库:

在Java中,包含6个整型类型元素的数组,就相当于上图中连在⼀起的6个⻋位,从上图中可以看到:

  • 数组的空间是连在⼀起的
  • 每个空间有⾃⼰的编号,起始位置的编号为0,即数组的下标。

那在程序中如何创建数组呢?

3.数组的创建及初始化

数组的创建

T [ ] 数组名 = new T[N];

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

T[ ]:表⽰数组的类型

N:表⽰数组的⻓度

java 复制代码
   public static void main(String[] args) {
        int[] array1 = new int[10];//创建⼀个可以容纳10个int类型元素的数组

        double[] array2 = new double[5];  //创建⼀个可以容纳5个double类型元素的数组

        String[] array3 = new String[3];  //创建⼀个可以容纳3个字符串元素的数组

    }

数组的初始化

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

1.动态初始化:在创建数组时,直接指定数组中元素的个数

int[ ] array = new int[10];

2.静态初始化:在创建数组时不直接指定数据元素个数,⽽直接将具体的数据内容进⾏指定

语法格式:T[ ] 数组名称 = {data1, data2, data3, ..., datan};

int[ ] array1 = new int[ ]{0,1,2,3,4,5,6,7,8,9};

double[ ] array2 = new double[ ]{1.0, 2.0, 3.0, 4.0, 5.0};

String[ ] array3 = new String[ ]{"hell", "Java", "!!!"};

【注意事项】

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

省去后面的new(和C语言有点像,只不过括号的位置不一样)

int[] array1 = {0,1,2,3,4,5,6,7,8,9};

double[] array2 = {1.0, 2.0, 3.0, 4.0, 5.0};

String[] array3 = {"hell", "Java", "!!!"};

数组也可以按照如下C语⾔⽅式创建,不推荐

int arr[] = {1, 2, 3};

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

java 复制代码
   public static void main(String[] args) {
        int[] array1;
        array1 = new int[10];
        int[] array2;
        array2 = new int[]{10, 20, 30};
    }

注意省略格式不可以拆分 , 否则编译失败,这种⽅式只能在定义的同时初始化

int[] array3;

array3 = {1, 2, 3};

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

如果数组中存储元素类型为基类类型,默认值为基类类型对应的默认值,⽐如:

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

复制代码
String\[\] words = new String\[3\];

4.数组的基本使⽤

数组中元素访问

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

java 复制代码
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]);
    }

输出:

也可以通过 [ ] 对数组中的元素进⾏修改

array[0] = 100;

System.out.println(array[0]);

输出:

【注意事项】

  • 数组是⼀段连续的内存空间,因此⽀持随机访问,即通过下标访问快速访问数组中任意位置的元素
  • 下标从0开始,介于[0,N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。

越界的情况:

java 复制代码
   public static void main(String[] args) {
        int[] array = {1, 2, 3};
        System.out.println(array[3]);
    }

结果报错:

使⽤数组⼀定要注意下标的访 问谨防越界.

遍历数组

所谓"遍历"是指将数组中的所有元素都访问⼀遍,访问是指对数组中的元素进⾏某种操作,⽐如:打 印。

java 复制代码
    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]);
    }

上述代码可以起到对数组中元素遍历的⽬的,但问题是:

  • 如果数组中增加了⼀个元素,就需要增加⼀条打印语句
  • 如果输⼊中有100个元素,就需要写100个打印语句
  • 如果现在要把打印修改为给数组中每个元素加1,修改起来⾮常⿇烦

通过观察代码可以发现,对数组中每个元素的操作都是相同的,则可以使⽤循环来进⾏打印。

java 复制代码
    public static void main(String[] args) {
        int[]array = new int[]{10, 20, 30, 40, 50};
        for(int i = 0; i < 5; i++){
            System.out.println(array[i]);
        }

    }

输出:

改成循环之后,上述三个缺陷可以全部2和3问题可以全部解决,但是⽆法解决问题1。那能否获取到数 组的**⻓度**呢?

注意:在数组中可以通过 数组对象 .length 来获取数组的⻓度

java 复制代码
    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遍历数组

java 复制代码
    public static void main(String[] args) {
        int[] array = {1, 2, 3};
        for (int x : array) {
            System.out.println(x);
        }
    }

输出:

for-each 是for 循环的另外⼀种使⽤⽅式.能够更⽅便的完成对数组的遍历.可以避免循环条件和更新语句写错.

二:数组是引⽤类型

1.初始JVM的内存分布

内存是⼀段连续的存储空间,主要⽤来存储程序运⾏时数据的。

⽐如:

  • 程序运⾏时代码需要加载到内存
  • 程序运⾏产⽣的中间数据要存放在内存
  • 程序中的常量也要保存
  • 有些数据可能需要⻓时间存储,⽽有些数据当⽅法运⾏结束后就要被销毁

如果对内存中存储的数据不加区分的随意存储,那对内存管理起来将会⾮常⿇烦。

因此JVM也对所使⽤的内存按照功能的不同进⾏了划分:

**程序计数器(PCRegister):**只是⼀个很⼩的空间,保存下⼀条执⾏的指令的地址

**虚拟机栈(JVMStack):**与⽅法调⽤相关的⼀些信息,每个⽅法在执⾏时,都会先创建⼀个栈帧,栈 帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的⼀些信息,保存的都是与⽅ 法执⾏时相关的⼀些信息。⽐如:局部变量。当⽅法运⾏结束后,栈帧就被销毁了,即栈帧中保存 的数据也被销毁了。

**本地⽅法栈(NativeMethodStack):**本地⽅法栈与虚拟机栈的作⽤类似.只不过保存的内容是 Native⽅法的局部变量.在有些版本的JVM实现中(例如HotSpot),本地⽅法栈和虚拟机栈是⼀起的

**堆(Heap):**JVM所管理的最⼤内存区域.使⽤new创建的对象都是在堆上保存(例如前⾯的 new int[]{1, 2, 3} ),堆是随着程序开始运⾏时⽽创建,随着程序的退出⽽销毁,堆中的数据只 要还有在使⽤,就不会被销毁

⽅法区(MethodArea):⽤于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后 的代码等数据.⽅法编译出的的字节码就是保存在这个区域

现在我们只简单关⼼堆和虚拟机栈这两块空间,后续JVM中还会更详细介绍。

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

基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值

引用数据类型创建的变量,⼀般称为对象的引⽤,其空间中存储的是对象所在空间的地址

java 复制代码
    public static void func() {
        int a = 10;
        int b = 20;
        int[] arr = new int[]{1,2,3};
    }

在上述代码中,a、b、arr,都是函数内部的变量,因此其空间都在main⽅法对应的栈帧中分配 a、b是内置类型的变量,因此其空间中保存的就是给该变量初始化的值

array是数组类型的引⽤变量,其内部保存的内容可以简单理解成是数组在堆空间中的⾸地址

从上图可以看到,引⽤变量并不直接存储对象本⾝,可以简单理解成存储的是对象在堆中空间的起始 地址。

通过该地址,引⽤变量便可以去操作对象。有点类似C语⾔中的指针,但是Java中引⽤要⽐指针 的操作更简单。

3.再谈引⽤变量

java 复制代码
    public static void func1() {
        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;
        array1[3] = 400;
        array2[4] = 500;
        for (int i = 0; i < array2.length; i++) {
            System.out.println(array2[i]);
        }
    }

图片解析:

4.认识null

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

java 复制代码
int[] arr = null;
System.out.println(arr[0]);

输出:

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

注意:java的null和0号地址并没有一定的关联

三:数组的应⽤场景

1.保存数据

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

输出:

2.作为函数的参数

参数传基本数据类型

java 复制代码
    public static void main(String[] args) {
        int num = 0;
        func(num);
        System.out.println("num = " + num);
    }
    public static void func(int x) {
        x = 10;
        System.out.println("x = " + x);
    }

输出:

发现在func⽅法中修改形参x的值,不影响实参的num值.

形参的改变不会影响实参

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

java 复制代码
    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]);
    }

输出:

发现在func⽅法内部修改数组的内容,⽅法外部的数组内容也发⽣改变.

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

3.作为函数的返回值

⽐如:获取斐波那契数列的前N项

java 复制代码
    public static void main(String[] args) {
            int[] array = fib(10);
            for (int i = 0; i < array.length; i++) {
                System.out.println(array[i]);
            }
        }
    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 < n; ++i){
            array[i] = array[i-1] + array[i-2];
        }
        return array;
    }

输出:

四:操作数组⼯具类Arrays

1.数组转字符串

使用Arrays 中 toString完成转换

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

输出:

使⽤这个⽅法后续打印数组就更⽅便⼀些.

Java 中提供了java.util.Arrays 包,其中包含了⼀些操作数组的常⽤⽅法.

2.数组拷⻉

使⽤ Arrays 中 copyof ⽅法完成数组的拷⻉:

java 复制代码
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6};
        //int[] newArr = arr;

        int[] newArr = Arrays.copyOf(arr, arr.length);
        System.out.println("newArr: " + Arrays.toString(newArr));
    }

输出:

注意:数组当中存储的是基本类型数据时,不论怎么拷⻉基本都不会出现什么问题,但如果存储的是 引⽤数据类型,拷⻉时需要考虑深浅拷⻉的问题,关于深浅拷⻉在后续详细给⼤家介绍

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

使用Arrays.sort进行自动排序

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

输出:

关于Arrays.sort 的具体实现算法,我们在后⾯的排序算法课上再详细介绍.到时候我们会介绍很多种常 ⻅排序算法

五:⼆维数组

1.普通的⼆维数组

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

基本语法

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

注意:行不可以省略,列可以省略

打印二维数组:

java 复制代码
    //二维数组打印
    public static void main(String[] args) {
        int[][]arr={{1,2,3},{3,4,5},{3,5,6}}; //三行两列
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                System.out.print(arr[i][j]+" ");
            }
            System.out.println();
        }

    }

输出:

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

2.不规则的⼆维数组

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

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

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

相关推荐
贵州晓智信息科技1 小时前
曼德勃罗集的 Three.js 实现
开发语言·javascript·ecmascript
xiaoshuaishuai81 小时前
C# CUDA 到 OpenCL 迁移
开发语言·windows·c#
asdfg12589631 小时前
一文理解“架构思维”
java·软件工程·软件开发·架构思维
AI科技星1 小时前
基于平行素数对等腰梯形网格拓扑的完备性证明哥德巴赫猜想1+1
c语言·开发语言·网络·量子计算·agi
聆风吟º1 小时前
【C标准库】深入理解C语言 isdigit函数详解:判断字符是否为数字
c语言·开发语言·库函数·isdigit
故事和你911 小时前
洛谷-【图论2-4】连通性问题1
开发语言·数据结构·c++·算法·动态规划·图论
RSCompany1 小时前
Frida 17 以后 Python API 跑旧版 JS 报 Java is not defined ?一行 import 直接恢复 Frida 16 体验
开发语言·python·逆向·hook·frida·android逆向·frida17
云烟成雨TD1 小时前
Spring AI Alibaba 1.x 系列【57】SAA Admin 前后端技术栈与分层设计详解
java·人工智能·spring
快乐的哈士奇1 小时前
对话框打字机效果:Vur + Java/Python 实现
java·开发语言·python