【Java SE语法篇】6.数组

在这里插入图片描述

📚博客主页:爱敲代码的小杨.

✨专栏:《Java SE语法》

❤️感谢大家点赞👍🏻收藏⭐评论✍🏻,您的三连就是我持续更新的动力❤️

文章目录

  • 1.数组的基本概念
    • 1.1 为什么使用数组?
    • 1.2 什么是数组
    • 1.3 数组的创建和初始化
      • 1.3.1 数组的创建
      • 1.3.2 数组的初始化
    • 1.4 数组的使用
      • 1.4.1 数组中元素访问
      • 1.4.2 遍历数组
  • 2.数组是引用类型
    • 2.1 JVM 内存分布
    • 2.2 基本类型的变量与引用类型变量的区别
    • 2.3 引用变量
    • 2.4 认识 null
  • 3. 数组应用场景
    • 3.1 保存数据
    • 3.2 作为方法的参数
    • 3.3 作为方法的返回值
  • 4. 二维数组
  • 5. 不规则数组

1.数组的基本概念

1.1 为什么使用数组?

假设现在要存储5个学生的年龄,按照之前掌握的知识点,我们会写出如下代码:声明5个变量存储学生变量

public class Test {
    public static void main(String[] args) {
        int age1;
        int age2;
        int age3;
        int age4;
        int age5;
    }
}

image-20240111144550855

如果我们有10个学生呢?我们就要声明20个变量,似乎没有什么问题。那如果有100,1000个学生呢,我们就要声明100,1000个变量,这样就有点离谱了,使用数组我们就可以解决一个问题。

1.2 什么是数组

数组,是指一组类型相同的数据的集合,数组中每个数据称为元素。数组可以存放任意类型的元素,但同一个数组里存放的元素类型必须一致。数组分为一维数组和多维数组。

数组在内存中是一段连续的空间,比如现实中的车库:

image-20240111144803139

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

  1. 数组中存放的元素其类型相同

  2. 数组的空间是连在一起的

  3. 每个空间有自己的编号,起始位置的编号为0,即数组的下标。

1.3 数组的创建和初始化

1.3.1 数组的创建

基本语法格式:

T[] 数组名 = new T[N];
  • T:表示数组中存放元素的类型
  • T[]:表示数组类型
  • N:表示数组的长度

代码示例:存储10个人的年龄

int[] ages = new int[10];

在这里插入图片描述

1.3.2 数组的初始化

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

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

    int[] ages = new int[10];
    
  2. 动态初始化:在创建数组是不直接指定数据元素个数,而直接讲具体的数据内容进行指定

    语法格式:

    T[] 数组名 = {data1,data2,....data};
    
    int[] ages = new {1,2,3,4,5};
    
    

【注意事项】

  • 静态初始化虽然没有指定数组的长度,编译器在编译时会根据{}中元素个数来确定数组的长度。

  • 静态初始化时, {}中数据类型必须与[]前数据类型一致。

  • 静态初始化可以简写,省去后面的new T[]。

    int[] arr = {1,3,2,5,4};
    // 注意:虽然省去了new T[], 但是编译器编译代码时还是会还原
    
  • 数组也可以按照如下C语言个数创建,不推荐

    int arr[] = {1, 2, 3};
    /*
    该种定义方式不太友好,容易造成数组的类型就是int的误解
    []如果在类型之后,就表示数组类型,因此int[]结合在一块写意思更清晰
    */
    
  • 静态和动态初始化也可以分为两步,但是省略格式不可以。

    public class Main {
        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};
        }
    }
    

    image-20240111153500205

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

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

      类型默认值
      byte0
      short0
      int0
      long0
      float0.0f
      double0.0
      char/u0000
      booleanfalse
    • 如果数组中存储元素类型为引用类型,默认值为null

1.4 数组的使用

1.4.1 数组中元素访问

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

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};

        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        System.out.println(arr[3]);
        System.out.println(arr[4]);
    }
}

【注意事项】:

  1. 数组是一段连续的内存空间,因此支持随机访问,即通过下标快速访问数组中任意位置的元素

  2. 下标从0开始,介于[0,N) 之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常。

    image-20240111185918318

    抛出了 java.lang.ArrayIndexOutOfBoundsException 异常. 使用数组一定要下标谨防越界.

1.4.2 遍历数组

所谓 “遍历” 是指将数组中的所有元素都访问一遍, 访问是指对数组中的元素进行某种操作,比如:打印。

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};

        System.out.println(arr[0]);
        System.out.println(arr[1]);
        System.out.println(arr[2]);
        System.out.println(arr[3]);
        System.out.println(arr[4]);
    }
}

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

  1. 如果数组中增加了一个元素,就需要增加一条打印语句

  2. 如果输入中有100个元素,就需要写100个打印语句

  3. 如果现在要把打印修改为给数组中每个元素加1,修改起来非常麻烦。

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

1. 循环遍历数组

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        for (int i = 0; i < 5; i++) {
            System.out.println(arr[i]);
        }
    }
}

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

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

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}

2. 使用 for-each 遍历数组

语法格式:

image-20240111194651510

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        for (int x : arr) {
            System.out.println(x);
        }
    }
}

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

for-each循环语句的循环变量将会遍历数组中的每个元素,而不是下标值。

3. 数组转字符串输出

import java.util.Arrays;

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3,4,5};
        String ret = Arrays.toString(arr);
        System.out.println(ret);
    }
}

代码分析:

image-20240111195534175

2.数组是引用类型

2.1 JVM 内存分布

内存是一段连续的存储空间,主要是用来存储程序运行时数据的。比如:

  1. 程序运行时代码需要加载到内存
  2. 程序运行产生的中间数据要存放在内存
  3. 程序中的常量也要保存
  4. 有些数据可能需要长时间存储,而有些数据当方法运行结束后就要被销毁。

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

image-20240111193146277

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

image-20240111193642529

  • 程序计数器:只是一个很小的空间,保存下一条执行的指令的地址
  • 虚拟机栈:与方法调用相关的一些信息,每个方法在执行时,都会先创建栈帧,栈帧中包含有:局部变量表、操作数栈、动态链接、返回地址以及其他的一些信息,保存的都是与方法执行时相关的一些信息。比如:局部变量。当方法运行结束后吧,栈帧就被销毁了,即栈帧中保存的数据也被销毁了
  • 本地方法栈:本地方法栈于虚拟机栈的作用类似,只不过保存的内容是方法的局部变量。在有些版本的 JVM 实现中,本地方法栈和虚拟机栈是一起的
  • 堆:JVM 所管理的最大内存区域,使用**new创建的对象都是在堆上保存,堆是随着程序开始运行时而创建,随着程序的结束而销毁,堆中的数据只要还有在使用,就不会被销毁**
  • 方法区:用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据。方法编译出的字节码就是保存在这个区域。

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

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

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

public class Main {
    public static void main(String[] args) {
        int a = 10;
        int[] arr = new int[]{1,2,3};
    }
}

在上述代码中,aarr,都是函数内部的变量,因此其空间都在main方法对应的栈帧中分配。
a是内置类型的变量,因此其空间中保存的就是给该变量初始化的值。
arr是数组类型的引用变量,其内部保存的内容可以简单理解成是数组在堆空间中的首地址。

image-20240111203129740

上图可以看出,引用变量并不直接存储对象本生,可以简单理解成存储的是对象在堆中空间的起始地址。通过该地址,引用变量便可以去操作对象。有点类似C语言中的指针,但是 Java 中引用要比指针的操作更简单。

2.3 引用变量

public class Main {
    public static void main(String[] args) {
        int[] arr1 = new int[3];
        arr1[0] = 1;
        arr1[1] = 2;
        arr1[2] = 3;

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

        arr1 = arr2;
        arr1[2] = 300;
        arr1[3] = 400;
        arr2[4] = 500;

        for (int x : arr1) {
            System.out.println(x);
        }
    }
}

image-20240111210502546

image-20240111211500185

2.4 认识 null

null 在 Java 中表示“空引用”,也就是一个不指向对象的引用

public class Main {
    public static void main(String[] args) {
        int[] arr = null;
        System.out.println(arr[0]);
    }
}

image-20240111213413800

null的作用类似于C语言中的NULL(空指针),都是表示一个无效的内存位置。因此不能对这个内存进行任何读写操作。一旦尝试读写,就会抛出NullPointerException

【注意】:Java 中并没有约定 null 和 0 下标地址的内存有任何关联。

3. 数组应用场景

3.1 保存数据

public class Main {
    public static void main(String[] args) {
        int[] arr = new int[]{1,2,3};
        for (int x : arr) {
            System.out.println(x);
        }
    }
}

3.2 作为方法的参数

  1. 参数传基本数据类型

    public class Main {
        public static void main(String[] args) {
            int num = 0;
            func(num);
            System.out.println("num = " + num);// 0
        }
    
        private static void func(int x) {
            x = 10;
            System.out.println("x = " + x); // 10
        }
    }
    

    上述代码我们可以发现func方法中修改了形参x的值,不影响实参的num值。

  2. 参数传引用数据类型

    public class Main {
        public static void main(String[] args) {
            int[] arr = new int[]{1,2,3};
            fun1(arr);
            System.out.println(Arrays.toString(arr)); // [1,2,3]
            
            fun2(arr);
            System.out.println(Arrays.toString(arr)); // [99,2,3]
        }
    
        public static void fun1(int[] arr) {
            arr = new int[]{11,22,33,44,55}; // 修改了形参的指向
        }
    
        public static void fun2(int[] arr) {
            arr[0] = 99; // 形参改变了实惨的值
        }
    }
    

    上述代码我们可以发现fun1方法中修改了形参的指向,不影响实参数组的值

    fun2方法内部修改了数组的内容,方法外部的数组内容也发生了改变。因为数组是引用类型,按照引用类型进行传递,是可以修改其中存放的内容的。

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

3.3 作为方法的返回值

public class Main {
    public static void main(String[] args) {
        int[] ret = fun();
        System.out.println(Arrays.toString(ret)); // [1, 2, 3, 4, 5]
    }
    public static int[] fun() {
        int[] arr = new int[]{1,2,3,4,5};
        return arr;
    }
}

4. 二维数组

二维数组本质上也就是一维数组,只不过每个元素又是一个一维数组

基本语法:

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

代码示例:

public class Main {
    public static void main(String[] args) {
        int[][] arr = {{1, 2, 3},{4,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();
        }
        System.out.println("=======");

        for (int[] tempArr : arr) {
            for (int x : tempArr) {
                System.out.print(x + " ");
            }
            System.out.println();
        }

        System.out.println("=======");
        String ret = Arrays.deepToString(arr); // deepToString()深度打印
        System.out.println(ret);
    }
}

Java 二维数组在定义的时候是可以省略列的

int[][] arr = new int[2][]; 

二维数组的用法和一维数组并没有明显差别, 因此我们不再赘述.
同理, 还存在 “三维数组”, “四维数组” 等更复杂的数组, 只不过出现频率都很低.

5. 不规则数组

代码示例:

public class Main {
    public static void main(String[] args) {
        int[][] arr = new int[2][];

        // 每一个一维数组 进行初始化
        arr[0] = new int[3];
        arr[1] = new int[5];

        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();
        }
    }
}
// 运行结果
0 0 0 
0 0 0 0 0 

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:/a/315396.html

如若内容造成侵权/违法违规/事实不符,请联系我们进行投诉反馈qq邮箱809451989@qq.com,一经查实,立即删除!

相关文章

Realm Management Extension领域管理扩展之安全状态

RME基于Arm TrustZone技术。TrustZone技术在Armv6中引入,提供以下两个安全状态: 安全状态(Secure state)非安全状态(Non-secure state)以下图表显示了在AArch64中的这两个安全状态以及通常在每个安全状态中找到的软件组件: 该架构将在安全状态运行的软件与在非安全状态运…

【Linux实用篇】Linux常用命令(1)

目录 1.1 Linux命令初体验 1.1.1 常用命令演示 1.1.2 Linux命令使用技巧 1.1.3 Linux命令格式 1.2 文件目录操作命令 1.2.1 ls 1.2.2 cd 1.2.3 cat 1.2.4 more 1.2.5 tail 1.2.6 mkdir 1.2.7 rmdir 1.2.8 rm 1.1 Linux命令初体验 1.1.1 常用命令演示 在这一部分中…

C#,卡特兰数(Catalan number,明安图数)的算法源代码

一、概要 卡特兰数&#xff08;英语&#xff1a;Catalan number&#xff09;&#xff0c;又称卡塔兰数、明安图数&#xff0c;是组合数学中一种常出现于各种计数问题中的数列。以比利时的数学家欧仁查理卡特兰的名字来命名。1730年左右被蒙古族数学家明安图使用于对三角函数幂…

Linux 【C编程】IO进阶— 阻塞IO、非阻塞IO、 多路复用IO、 异步IO

文章目录 1.阻塞IO与非阻塞IO1.1为什么有阻塞式&#xff1f;1.2非阻塞 2.阻塞式IO的困境3.并发IO的解决方案3.1非阻塞式IO3.2多路复用IO3.2.1什么是多路复用IO&#xff1f;3.2.1多路复用IO select原理3.2.1多路复用IO poll原理 3.3异步IO 1.阻塞IO与非阻塞IO 1.1为什么有阻塞式…

国产麒麟系统开机没有网络需要点一下这个设置

问题描述&#xff1a; 一台国产电脑网线连接正常&#xff0c;打开网页后显示无法访问&#xff0c;那么是什么原因无法上网呢&#xff1f;下面就告诉你一个小方法去解决一下这个问题&#xff1b; 检查故障&#xff1a; 检测交换机、网线、水晶头全都正常&#xff0c;同房间摆放的…

ZooKeeper 实战(二) 命令行操作篇

文章目录 ZooKeeper 实战(二) 命令行操作篇1. 服务端命令1.1. 服务启动1.2. 查看服务1.3. 重启服务1.4. 停止服务 2. 客户端命令2.1. 启动客户端2.2. 查看节点信息查看根节点详情 ls -s /添加一个watch监视器 ls -w /列举出节点的级联节点 ls -R / 2.3. 查看节点状态2.4. 创建节…

Jenkins 问题

从gitlab 仓库拉去代码到Jenkins本地报错 ERROR: Couldn’t find any revision to build. Verify the repository and branch configuration for this job. 问题原因&#xff1a; 创建条目》配置的时候&#xff0c;gitlab仓库不存在master分支 修复后&#xff1a;

44-js return返回值,全局作用域,局部作用域,隐式作用域,变量的生命周期,delete释放内存

1.return返回值&#xff1a;函数执行后剩下结果就是返回值。 function fn(a,b,c){//return返回值return(abc);// console.log("aaa"); //return之后的值都不在执行了// alert("bbb"); //return之后的值不在执行了}console.log(fn(1,2,3)*10)…

人工智能:我的学习之旅与认知探索(第1版)

&#x1f31f;&#x1f30c; 欢迎来到知识与创意的殿堂 — 远见阁小民的世界&#xff01;&#x1f680; &#x1f31f;&#x1f9ed; 在这里&#xff0c;我们一起探索技术的奥秘&#xff0c;一起在知识的海洋中遨游。 &#x1f31f;&#x1f9ed; 在这里&#xff0c;每个错误都…

what is BERT?

BERT Introduction Paper 参考博客 9781838821593_ColorImages.pdf (packt-cdn.com) Bidirectional Encoder Representation from Transformer 来自Transformer的双向编码器表征 基于上下文&#xff08;context-based&#xff09;的嵌入模型。 那么基于上下文&#xff08;…

golang学习笔记——go语言多文件项目运行的四种方式

go语言多文件运行技巧 有两个源码文件的go语言项目如何运行? go.modmain.go Trie.go 如何直接运行go run main.go会提示找不到文件。 # 在windows10下运行 $ go run main.go # command-line-arguments .\main.go:6:9: undefined: Constructor是真的找不到文件吗。其实不是。…

一个成功的camera案例:ros2+gazebo+摄像头

各位看&#xff1a;随着大物体的移动&#xff0c;在涉嫌头的位置也发生了改变-----右上角那个/camera的位置也变了 右上角那个是摄像头图案&#xff0c;以下是仓库链接&#xff1a; ros-ign-gazebo-camera: https://github.com/arashsm79/ros-ign-gazebo-camera.git一个ros2摄…

基于多智能体点对点转换的分布式模型预测控制

matlab2020正常运行 基于多智能体点对点转换的分布式模型预测控制资源-CSDN文库

Zabbix“专家坐诊”第223期问答汇总

来源&#xff1a;乐维社区 问题一 Q&#xff1a;Zabbix 5.0安装完mysql之后怎么备份&#xff1f;忘记mysql当时创建的密码了&#xff0c;怎么样能查看设置的密码&#xff1f; A&#xff1a;mysql初始化密码在 /var/log/mysqld.log中可以看到&#xff0c;搜关键字temporary pas…

膜结构球形影院为观众打造观影新体验

在数字科技快速发展的当下&#xff0c;轻空间公司打破传统影院的束缚&#xff0c;领航未来娱乐体验的创新浪潮。膜结构球形影院问世&#xff0c;它不仅仅是一个娱乐场所&#xff0c;更是一场極致沉浸感的感官之旅&#xff0c;为观众带来震撼性的视听冲击。 沉浸式体验的新纪元 …

Jenkins安装和配置

拉取Jenkins镜像 docker pull jenkins/jenkins 编写jenkins_docker.yml version: "3.1" services:jenkins:image: jenkins/jenkinscontainer_name: jenkinsports:- 8080:8080- 50000:50000volumes:- ./data/:/var/jenkins_home/首次启动会因为数据卷data目录没有权限…

Nginx配置负载均衡实例

Nginx配置反向代理实例二 提醒一下&#xff1a;下面实例讲解是在Mac系统演示的&#xff1b; 负载均衡实例实现的效果 浏览器地址栏输入地址http://192.168.0.101/test/a.html&#xff0c;刷新页面进行多次请求&#xff0c;负载均衡效果&#xff0c;平均分配到8080端口服务和8…

DNS解析和它的三个实验

一、DNS介绍 DNS&#xff1a;domain name server 7层协议 名称解析协议 tcp /53 主从之间的同步 udp/53 名字解析 DNS作用&#xff1a;将域名转换成IP地址的协议 1.1DNS的两种实现方式 1.通过hosts文件&#xff08;优先级最高&#xff09; 分散的管理 linux /etc/hos…

资源三号03星-立体测绘卫星星座

资源三号03星作为我国民用高分辨率立体测图卫星资源三号系列的第三颗卫星&#xff0c;在资源三号02星技术状态的基础上进行了继承和适当优化&#xff0c;设计寿命由资源三号02星的5年延长至8年&#xff0c;星上搭载了三线阵立体测绘相机、多光谱相机和业务化应用的激光测高仪&a…

【JAVA】concurrentHashMap和HashTable有什么区别

&#x1f34e;个人博客&#xff1a;个人主页 &#x1f3c6;个人专栏&#xff1a;JAVA ⛳️ 功不唐捐&#xff0c;玉汝于成 目录 前言 正文 同步性质&#xff1a; 性能&#xff1a; 允许空键值&#xff08;Allow Nulls&#xff09;&#xff1a; 迭代器&#xff08;Iter…