Java中的数组
前言:
本篇博客将为大家介绍Java中的数组的相关知识。
目录
基本介绍
概念相关
数组的使用
数组是引用类型
应用场景
保存数据
作为方法的参数
作为方法的返回值
练习
数组转字符串
数组拷贝
求数组中元素的平均值
查找数组中的指定元素(二分查找+顺序查找)
数组排序(冒泡排序)
数组逆序
二维数组
基本介绍
概念相关
数组可以看成是相同类型元素的集合。在内存中是一段连续的空间,每个空间都有自己的编号,编号从0开始。
数组的使用
- 创建数组:T[] 数组名 = new T[N];
- T表示数组中存放的元素的数据类型
- T[]表示数组的类型
- N表示数组的长度
- 数组的初始化(一共有三种形式):
- 动态初始化:在创建数组时,直接指定数组元素的个数
- int[] arr = new int[10];
- 静态初始化:在创建数组的时候,不直接指定数组元素个数,而是对元素的具体内容进行指定
- int[] arr = new int[]{12,23,43,21,43};
- int[] arr = {12,23,43,21,43};(对上面的写法再次进行简化)
- 注意:
- 静态初始化虽然没有指定数组的长度,但是编译器会按照其存放的元素的个数来确定其长度
- 静态初始化中的后面的new T[]虽然可以省略,但在编译的时候还是会还原的
- 数组也可以按照C语言中数组的创建方式来创建,但是不推荐。T[]写在一起更加清晰明了,让人立刻就明白T[]是数组的类型
- 静态初始化和动态初始化都可以写成两步,但是省略后面new T[]的静态静态初始化方法不可以

- 如果没有对数组初始话,里面存放的是默认值。基本数据类型存基本数据类型的默认值;引用类型存引用类型的默认值。
- 基本数据类型的默认值:
- 动态初始化:在创建数组时,直接指定数组元素的个数
- 数组的使用:
- 数组中元素的访问:数组在内存中是一段连续空间,空间的编号都是从0开始,依次递增,该编号称为数组的下标,数组可以通过其下标访问数组中的任意元素(即,支持随机访问)。其编号是从)开始的,假设数组中共有N个元素,那么编号,也就是下标的大小只能在[0,N)这个范围,大于等于N都会导致数组越界(java.lang.ArrayIndexOutOfBoundsException)。

- 遍历数组:所谓遍历,就是把数组中的元素全部访问一遍;访问是指对数组中的元素进行某种操作,这里以打印为例。像数组中的元素的访问的例子那样,arr6中的所有元素都可以通过一个一个地打印出来,从而达到遍历的效果。但是我们不禁思考:如果一个数组有很多元素呢(比如100个),我们也要这样一个一个地去敲每一步的打印吗?这么做的工作量显然十分巨大。仔细思考,我们会发现我们可以通过循环很容易实现遍历,从而减少代码量:
- 我们可以通过for-each循环来遍历:

- 就通过for循环来实现:(当然,其他循环也是可以的,这里也可以只是举例)
- 这时,另外一个疑问又来了:我们要如何去获取数组的长度呢?此处我们自己举例写的arr6数组,且可以看到它的长度(起码我们可以自己数一下),但是总是有一些场景我们是不能确定其长度或者长度在改变的,那么我们要如何获取数组的长度呢?我们可以通过”数组对象.length“来获取其长度

- 这时,另外一个疑问又来了:我们要如何去获取数组的长度呢?此处我们自己举例写的arr6数组,且可以看到它的长度(起码我们可以自己数一下),但是总是有一些场景我们是不能确定其长度或者长度在改变的,那么我们要如何获取数组的长度呢?我们可以通过”数组对象.length“来获取其长度
- 我们可以通过for-each循环来遍历:
- 数组中元素的访问:数组在内存中是一段连续空间,空间的编号都是从0开始,依次递增,该编号称为数组的下标,数组可以通过其下标访问数组中的任意元素(即,支持随机访问)。其编号是从)开始的,假设数组中共有N个元素,那么编号,也就是下标的大小只能在[0,N)这个范围,大于等于N都会导致数组越界(java.lang.ArrayIndexOutOfBoundsException)。
数组是引用类型
首先,我们先基本了解一下JVM:

程序计数器(PC Register):一块很小的空间,保存下一条执行指令的地址。
虚拟机栈(JVM Stack):与方法调用的一些相关信息,每个方法在执行的时候,都会先创建一个栈帧,栈帧中包含有:局部变量表、操作数栈,动态链接,返回地址以及一些其他的信息,保存的都是一些和方法执行时的相关信息。如:局部变量。方法在运行完以后,栈帧就会被销毁,即保存在栈帧中的数据也会被销毁。
本地方法栈(Native Method Stack):本地方法栈和虚拟机栈相似,只不过保存的是Native方法的局部变量。有些版本的JVM(如HotSpot)实现中本地方法栈和虚拟机栈是一起的。
堆(Head):JVM所管理的最大内存区域,使用new创建的对象都是在堆上保存的。堆是随着程序开始运行时而创建的,随着程序的退出而销毁,堆中的数据只要还有在使用的,就不会被销毁。
方法区(Method Area):用于存储已经被虚拟机加载的类信息,常量、静态变量、即时编译器编译后的代码等数据。方法编译出的字节码就是保存在这个区域的。
接下来,我们将主要涉及两个部分:堆和虚拟机。
基本数据类型创建的变量,称为基本变量,该变量空间存放的就是其保存的值;
而引用数据类型创建的变量,一般称为对象的引用,其空间存放的对象的地址。
举例:
注意:
- 对于这种写法(如下图),我们不能说一个引用指向了一个引用(这句话是错的,引用不能指向引用),我们应该说,一个引用指向了另一个引用所指向的对象

图解:
- 在Java中,null表示空引用,也就是不指向任何对象的引用

- Java中并没有约定null和0有任何关系。
应用场景
保存数据

作为方法的参数

图解:
作为方法的返回值

把func3方法中返回的arr的地址给了ret,使得ret指向了ret这个引用指向的地址(func3中的代码也可以直接简化成return new int[]{1,2,3};)
注意:对象一定是在堆上的,引用变量不一定是在栈上的。
练习
数组转字符串

记得要导包:import java.util.Arrays;(java.util.Arrays包里面包含了一些操作数组的常用方法)
我们也可以自己尝试实现一下这个方法:
public class Demo3 { public static String myToString(int[] arr){String ret ="[";for (int i = 0; i < arr.length; i++) {ret += arr[i];if(i != arr.length -1){ret += ",";}}ret += "]";return ret;}public static void main(String[] args) {int[] arr = {1,2,3};System.out.println(myToString(arr));}
}
数组拷贝
单纯的拷贝:
这里要注意,不能直接int[] copy = arr; 这样不是拷贝,是让copy拿到了arr里面放的地址,从而指向了它指向的引用,并没有创建新的数组,不是拷贝。
法二:
直接利用Arrays自带的拷贝方法(copyOf(原数组,新数组长度)):
值得注意的是:copyOf方法有很多方法和它构成重载,我们只需要在选择满足自己需求的那个即可。
copyOf方法还可以改变新的数组的长度:
拷贝一定范围的数据:
copyOfRang(原数组,初始拷贝下标,结束拷贝下标):


如果拷贝的范围超出了原来数组的长度,就只能能拷贝多少拷贝多少,那些没拷贝到的就还是初始值0。 
System.arraycopy(原数组,原数组开始被拷贝的下标,新数组,新数组开始拷贝的下标,拷贝的长度);

注意:方法中的最后一个数是从原数组中拷贝过来的数据的长度要格外小心是否越界,要注意在起始拷贝下标的基础上新数组是否能接收这么长的数据,原数组是否能给出这么多的数据供拷贝。
求数组中元素的平均值
import java.util.Arrays;
public class Demo3 {
public static double avg(int[] arr){int sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}return sum/(double)arr.length;//注意类型转换}public static void main(String[] args) {int[] arr = {1,2,3,4,5,6,7,8,21};System.out.println(avg(arr));}
}

查找数组中的指定元素(二分查找+顺序查找)
顺序查找:
import java.util.Arrays;
public class Demo3 {//顺序查找:public static int findVal(int[] arr, int i){for (int j = 0; j < arr.length; j++) {if(arr[j] == i){return j;}}return -1;//数组下标不可能是负数,返回负数说明没有找到}public static void main(String[] args) {int[] arr = {1,2,3,4};int ret = findVal(arr,2);System.out.println(ret);}
}

二分查找:针对有序数组,我们还可以通过二分查找来找出要查找的数据的下标:
public class Demo3 {
// 二分查找:public static int binarySearch(int[] arr, int i){int left = 0;int right = arr.length - 1;while(left <= right){int mid = (right + left)/2;if(arr[mid] < i){left = mid + 1;mid = (right + left)/2;}else if(arr[mid] > i){right = mid - 1;mid = (right + left)/2;}else if(arr[mid] == i){return mid;}}return -1;}public static void main(String[] args) {int[] arr = {12,34,45,51,54,65,76,87,97,99};int ret = binarySearch(arr,51);System.out.println(ret);}
}

图解:

当然,我们也可以通过二分查找查找无序的数组的特定元素:先通过Arrays里面的sort方法对数组进行排序(升序),然后再通过二分查找查出排序好以后的特定数组的下标,不过这样做的意义其实并不大,因为经过排序,数组的下标早已不是原来的样子了。
数组排序(冒泡排序)
import java.util.Arrays;
public class Demo3 { //冒泡排序:public static void bubbleSort(int[] arr){for (int i = 0; i < arr.length-1; i++) {//一共要排arr.length-1次序,每排一次都会让数组中的一个数有序(此处以最大值为例)for (int j = 0; j < arr.length-i-1; j++) {//每一次排序内部要走arr.length-1-i次排序,才能实现让数组中为排好序的数里面的最大值排到最后if(arr[j]>arr[j+1]){int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;}}}}public static void main(String[] args) {int[] arr = {12,45,97,76,51,34,87,54,65,99};bubbleSort(arr);System.out.println(Arrays.toString(arr));}
}
由图可知,在i=4开始,数组就已经是有序的了,后面的比较就是冗余的了,所以我们可以再对这个代码进行优化:在方法中加一个变量用来判断是否发生了交换,且每有一趟循环走完开始下一趟循环的时候就要让这个变量变回到它原来的值。一旦发现不再发生交换的时候,就直接跳出循环。
import java.util.Arrays;
public class Demo3 { //冒泡排序:public static void bubbleSort(int[] arr){for (int i = 0; i < arr.length-1; i++) {//一共要排arr.length-1次序,每排一次都会让数组中的一个数有序(此处以最大值为例)boolean flg = false;//每一趟开始的时候都要让flg为falsefor (int j = 0; j < arr.length-i-1; j++) {//每一次排序内部要走arr.length-1-i次排序,才能实现让数组中为排好序的数里面的最大值排到最后if(arr[j]>arr[j+1]){int tmp = arr[j];arr[j] = arr[j+1];arr[j+1] = tmp;flg = true;//若发生交换,则改变flg的值,通过flg的值来确定是否发生交换,若未发生交换,则直接跳出循环}}if(flg == false){break;}}}public static void main(String[] args) {int[] arr = {12,45,97,76,51,34,87,54,65,99};bubbleSort(arr);System.out.println(Arrays.toString(arr));}
}
数组逆序
此处介绍的是直接通过交换对应下标的元素来实现数组逆序的效果。
import java.util.Arrays;
public class Demo3 { //数组逆序:public static void reserve(int[] arr){int left = 0;int right = arr.length-1;while(left < right){//不用管相等的情况,因为当right和left相等时就表明相等的那个数就是中间的那个,// 既然在最中间,也没有交换的必要了int tmp = arr[left];arr[left] = arr[right];arr[right] = tmp;left++;right--;}}public static void main(String[] args) {int[] arr = {12,45,97,76,51,34,87,54,65,99};reserve(arr);System.out.println(Arrays.toString(arr));}
}

二维数组
- 语法:数据类型[][] 数组名称 = new 数据类型[行数][列数]{初始化数据};
- int[][] arr = new int[][]{{1,2,3},{4,5,6}};
- int[][] arr = {{1,2,3},{4,5,6}};
- int[][] arr = new int[2][3];(默认这两行三列里面存的全是0)
- 二维数组本质上也是一个数组,只不过每个数组里面又是一个数组。行里面存放的是各个列组成的的数组的地址。

- 遍历二维数组:
- 我们很容易想到一个最简单粗暴的方法:通过两层循环来遍历整个数组:

- 但是很明显,对于这种方法,我们是自己手动置入其行和列的长度的。有没有办法可以获取到其行和列的长度吗?当然是有的。结合前面介绍的二维数组的元素其实就是一维数组,我们可以很好地理解下面这种写法:

- 我们很容易想到一个最简单粗暴的方法:通过两层循环来遍历整个数组:
- 顺便一提,要想直接打印出二维数组,我们使用的方法不再是toString,而是deepToString

- 不规则的二维数组:
- 注意,未对不规则二维数组初始化的时候不能打印它。因为二位数组里面存的是一维数组,而数组是引用类型,引用类型未初始化默认存储的是null,也就是不指向任何地址,所以会报空指针异常的错误。
Arrays中的其他方法的介绍:
- equals:判断两个数组是否一样:

- fill:帮助数组填充数据:

同时,fill方法有很多重载方法,可以根据需求选择,如:把某个值从数组的n1下标填充到n2下标
相关文章:
Java中的数组
前言: 本篇博客将为大家介绍Java中的数组的相关知识。 目录 基本介绍 概念相关 数组的使用 数组是引用类型 应用场景 保存数据 作为方法的参数 作为方法的返回值 练习 数组转字符串 数组拷贝 求数组中元素的平均值 查找数组中的指定元素(二…...
Java反射调用jar包实现多态
上一篇实现了反射调用jar包,但是没有实现多态,这次先给自己的jar包类抽象一个接口,然后实现类实现接口。最后调用放反射得到的对像转换成接口类型调用执行。 定义接口,指定包为ZLZJar package ZLZJar;public interface ITest {p…...
PowerBI 一些基础功能
1、PowerBI创建日期表 1.1、Power BI 日期表 - 知乎日期是做数据分析的时候使用最频繁的分析维度,一般建议建立单独的日期维度表,并与事实表的日期字段建立连接。 建立日期维度表可通过DAX函数的方式进行: 日期表 CALENDAR(DATE("2023&…...
Mac用命令行安装Adobe代码字体Source Code Pro
执行命令 brew tap homebrew/cask-fonts && brew cask install font-source-code-pro...
RustDay05------Exercise[31-40]
31.结构体申明 结构体在这里给了三种声明样式 (1)字典样式的键值对(使用花括号) (2)元组样式的数值元组(使用圆括号) (3)空结构体,可以被格式化输出名字 // structs1.rs // Address all the TODOs to make the tests pass! // Execute rustlings hint structs1 or use the…...
wireshark过滤器的简单介绍
wireshark过滤器的简单介绍 Wireshark的过滤器主要分为捕获过滤器和显示过滤器两种,其中捕获过滤器在数据包捕获时起作用,而显示过滤器用于在已捕获的数据包的集合中筛选数据。以下是一些Wireshark过滤器的详细介绍: 捕获过滤器:…...
数据结构:二叉树(1)
目录 树的概念 树的表示形式 二叉树 二叉树的性质 题目 二叉树的存储 链式存储 初始化二叉树 二叉树的遍历 前序遍历:根👉左子树👉右子树 中序遍历:左子树👉根👉右子树 后序遍历:左子…...
[nlp] chathome—家居装修垂类大语言模型的开发和评估
ChatHome: Development and Evaluation of a Domain-Specific LanguageModel for Home Renovation ChatHome: 家居装修垂类大语言模型的开发和评估 1、摘要: 我们的方法包括两个步骤:首先,使用广泛的家庭装修数据集(包括专业文章、标准文档和网络内容)对通用模型进行后预训…...
http(下)
http的工作流程: 客户端---服务端通信过程 请求----响应的模型 建立连接:tcp/ip协议与服务器建立连接(三次握手),客户端向服务器的80端口发送连接请求 发送请求:一旦连接建立之后,客户端就像…...
Python学习基础笔记七十二——IDE集成开发环境
集成开发环境,英文缩写是IDE。 IDE可以帮你更高效地开发项目代码。因为它提供了非常实用的功能,比如项目文件管理、语法高亮、代码导航、自动补齐代码、语法静态检查、调试、版本控制等等。 两款IDE:Pycharm和VSCode。 pycharm中的代码文件都…...
[MQ]Win平台RocketMQ安装启动
1、下载 官网下载地址:https://rocketmq.apache.org/zh/download 2、解压ZIP包 解压rocketmq-all-x.x.x-bin-release.zip到目录。 比如我解压到了E:\Env\MQ_rocket\rocketmq-all-5.1.4-bin-release 3、配置环境变量 ROCKETMQ_HOME 4、RocketMQ JVM内存配置 这个需要…...
vscode工程屏蔽不使用的文件夹或文件的方法
一. 简介 vscode是一款 微软提供的免费的代码编辑软件。 对于 IMX6ULL-ALPHA开发板而言,NXP官方uboot一定会支持不止 IMX6ULL芯片的代码,也不止支持 一种架构,还支持其他芯片或架构的源码文件。 为了方便阅读代码,vscode软件可…...
黑马JVM总结(三十四)
(1)JMM概述 (2)JMM-原子性-synchronized java内存模型是如何保证原子性的呢,它是通过synchroized关键字,来达到这个目的的 第一个线程来了进入同步代码块之后,把这个对象加上锁了,…...
[linux]vncserver常用终端命令合集
开启vnc服务:systemctl start vncserver:1.service 关闭vnc服务:systemctl stop vncserver:1.service 重启vnc服务:systemctl restart vncserver:1.service 设置VNC密码: vncpasswd 开启VNC: vncserver :1 关闭VNC࿱…...
亚马逊、eBay,速卖通,国际站买家账号支付异常问题解决方法
如何解决下单被砍、封号问题,建议采取以下措施: 买家账号下单,不单纯只是解决支付卡、IP问题就可以了,因为平台大数据风控点很多, 我们防关联具体要解决几个问题 一:要硬件参数的关联、安全码、地区码、…...
Constitutional AI
用中文以结构树的方式列出这篇讲稿的知识点: Although you can use a reward model to eliminate the need for human evaluation during RLHF fine tuning, the human effort required to produce the trained reward model in the first place is huge. The label…...
TDengine 资深研发整理:基于 SpringBoot 多语言实现 API 返回消息国际化
作为一款在 Java 开发社区中广受欢迎的技术框架,SpringBoot 在开发者和企业的具体实践中应用广泛。具体来说,它是一个用于构建基于 Java 的 Web 应用程序和微服务的框架,通过简化开发流程、提供约定大于配置的原则以及集成大量常用库和组件&a…...
数据结构-冒泡排序Java实现
目录 一、引言二、算法步骤三、原理演示四、代码实战五、结论 一、引言 冒泡排序是一种基础的比较排序算法,它的思想很简单:重复地遍历待排序的元素列表,比较相邻元素,如果它们的顺序不正确,则交换它们。这个过程不断重…...
完整教程:Java+Vue+Websocket实现OSS文件上传进度条功能
引言 文件上传是Web应用开发中常见的需求之一,而实时显示文件上传的进度条可以提升用户体验。本教程将介绍如何使用Java后端和Vue前端实现文件上传进度条功能,借助阿里云的OSS服务进行文件上传。 技术栈 后端:Java、Spring Boot 、WebSock…...
【微服务 SpringCloud】实用篇 · 服务拆分和远程调用
微服务(2) 文章目录 微服务(2)1. 服务拆分原则2. 服务拆分示例1.2.1 导入demo工程1.2.2 导入Sql语句 3. 实现远程调用案例1.3.1 案例需求:1.3.2 注册RestTemplate1.3.3 实现远程调用1.3.4 查看效果 4. 提供者与消费者 …...
多层PCB结构设计与过孔工艺全解析
1. 多层PCB内部结构全解析作为一名硬件工程师,第一次拆解十层PCB板时,那种震撼感至今难忘。密密麻麻的过孔像微型城市的地下管网,精密排布的走线堪比神经脉络。今天我就用最直观的立体解剖图,带你看透这些"电子乐高"的搭…...
零基础入门Python爬虫:借助快马AI生成你的第一个可运行爬虫脚本
今天想和大家分享一下我作为Python爬虫新手的学习经历。刚开始接触爬虫时,面对各种库和概念真的有点懵,直到发现了InsCode(快马)平台,它让我用自然语言描述需求就能生成可运行的代码,大大降低了入门门槛。 爬虫的基本原理 爬虫就像…...
终极指南:如何让2012-2015年老款Mac安装最新macOS系统
终极指南:如何让2012-2015年老款Mac安装最新macOS系统 【免费下载链接】OpenCore-Legacy-Patcher Experience macOS just like before 项目地址: https://gitcode.com/GitHub_Trending/op/OpenCore-Legacy-Patcher 您的2012-2015年老款Mac是否已被苹果官方抛…...
WSL+VSCode+Jupyter+R配置总结(2026年)
题记:网上相关的资料很多了,现阶段跟随AI也能少走很多弯路,但体验下来依旧有些细节没有被很好的提及,故写本文一方面作为自己的备忘录,一方面希望帮助更多像我一样的新手。 用了上述的配置跑了scanpy一年多了…...
STM32F407ZGT6最小系统:从原理图到PCB的实战设计解析
1. STM32F407ZGT6最小系统设计入门 第一次接触STM32F407ZGT6最小系统设计时,我也被各种专业术语和复杂的电路图搞得晕头转向。但经过几个项目的实战后,我发现只要掌握几个关键模块,设计一个稳定可靠的最小系统其实并不难。STM32F407ZGT6是STM…...
3个高效功能让视频创作者轻松生成专业字幕
3个高效功能让视频创作者轻松生成专业字幕 【免费下载链接】video-srt-windows 这是一个可以识别视频语音自动生成字幕SRT文件的开源 Windows-GUI 软件工具。 项目地址: https://gitcode.com/gh_mirrors/vi/video-srt-windows 工具概述 VideoSrt是一款基于Golang开发的…...
Pixel Dream Workshop 快速上手:Python 零基础入门到生成第一幅AI画作
Pixel Dream Workshop 快速上手:Python 零基础入门到生成第一幅AI画作 1. 前言:为什么选择Pixel Dream Workshop 如果你对AI绘画感兴趣但苦于没有编程基础,这篇教程就是为你量身定制的。Pixel Dream Workshop是一个对新手极其友好的AI绘画工…...
Qwen-Ranker Pro快速部署:Windows WSL2环境下Streamlit兼容性方案
Qwen-Ranker Pro快速部署:Windows WSL2环境下Streamlit兼容性方案 1. 环境准备与系统要求 在Windows WSL2环境中部署Qwen-Ranker Pro需要确保系统满足以下基本要求: 硬件要求: 内存:至少8GB RAM(推荐16GB以上&…...
从用户视角优化:让QGC地面站的盘旋半径显示更直观的3个实用技巧
从用户视角优化:让QGC地面站的盘旋半径显示更直观的3个实用技巧 在无人机飞行任务规划中,盘旋半径的准确显示直接关系到飞行安全和任务执行效率。QGroundControl(QGC)作为业界领先的开源地面站软件,其功能强大但某些细…...
高效双电源自动切换电路的设计与实现
1. 双电源自动切换电路的应用场景 双电源自动切换电路在现代电子设备中扮演着关键角色,它能确保设备在不同供电来源之间无缝切换,避免断电导致的系统崩溃。这种电路设计特别适合以下场景: 便携式设备:比如蓝牙音箱、移动电源等&am…...
