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. 提供者与消费者 …...
云计算——弹性云计算器(ECS)
弹性云服务器:ECS 概述 云计算重构了ICT系统,云计算平台厂商推出使得厂家能够主要关注应用管理而非平台管理的云平台,包含如下主要概念。 ECS(Elastic Cloud Server):即弹性云服务器,是云计算…...

阿里云ACP云计算备考笔记 (5)——弹性伸缩
目录 第一章 概述 第二章 弹性伸缩简介 1、弹性伸缩 2、垂直伸缩 3、优势 4、应用场景 ① 无规律的业务量波动 ② 有规律的业务量波动 ③ 无明显业务量波动 ④ 混合型业务 ⑤ 消息通知 ⑥ 生命周期挂钩 ⑦ 自定义方式 ⑧ 滚的升级 5、使用限制 第三章 主要定义 …...

Docker 运行 Kafka 带 SASL 认证教程
Docker 运行 Kafka 带 SASL 认证教程 Docker 运行 Kafka 带 SASL 认证教程一、说明二、环境准备三、编写 Docker Compose 和 jaas文件docker-compose.yml代码说明:server_jaas.conf 四、启动服务五、验证服务六、连接kafka服务七、总结 Docker 运行 Kafka 带 SASL 认…...

基于uniapp+WebSocket实现聊天对话、消息监听、消息推送、聊天室等功能,多端兼容
基于 UniApp + WebSocket实现多端兼容的实时通讯系统,涵盖WebSocket连接建立、消息收发机制、多端兼容性配置、消息实时监听等功能,适配微信小程序、H5、Android、iOS等终端 目录 技术选型分析WebSocket协议优势UniApp跨平台特性WebSocket 基础实现连接管理消息收发连接…...

【单片机期末】单片机系统设计
主要内容:系统状态机,系统时基,系统需求分析,系统构建,系统状态流图 一、题目要求 二、绘制系统状态流图 题目:根据上述描述绘制系统状态流图,注明状态转移条件及方向。 三、利用定时器产生时…...
Linux离线(zip方式)安装docker
目录 基础信息操作系统信息docker信息 安装实例安装步骤示例 遇到的问题问题1:修改默认工作路径启动失败问题2 找不到对应组 基础信息 操作系统信息 OS版本:CentOS 7 64位 内核版本:3.10.0 相关命令: uname -rcat /etc/os-rele…...
DiscuzX3.5发帖json api
参考文章:PHP实现独立Discuz站外发帖(直连操作数据库)_discuz 发帖api-CSDN博客 简单改造了一下,适配我自己的需求 有一个站点存在多个采集站,我想通过主站拿标题,采集站拿内容 使用到的sql如下 CREATE TABLE pre_forum_post_…...
OCR MLLM Evaluation
为什么需要评测体系?——背景与矛盾 能干的事: 看清楚发票、身份证上的字(准确率>90%),速度飞快(眨眼间完成)。干不了的事: 碰到复杂表格(合并单元…...

车载诊断架构 --- ZEVonUDS(J1979-3)简介第一篇
我是穿拖鞋的汉子,魔都中坚持长期主义的汽车电子工程师。 老规矩,分享一段喜欢的文字,避免自己成为高知识低文化的工程师: 做到欲望极简,了解自己的真实欲望,不受外在潮流的影响,不盲从,不跟风。把自己的精力全部用在自己。一是去掉多余,凡事找规律,基础是诚信;二是…...

Vue3 PC端 UI组件库我更推荐Naive UI
一、Vue3生态现状与UI库选择的重要性 随着Vue3的稳定发布和Composition API的广泛采用,前端开发者面临着UI组件库的重新选择。一个好的UI库不仅能提升开发效率,还能确保项目的长期可维护性。本文将对比三大主流Vue3 UI库(Naive UI、Element …...