Java——二维数组

news2024/11/26 9:46:25

一、二维数组介绍

二维数组与一维数组很相似。可以说二维数组是元素为一维数组的数组,也就是一维数组的数组。每个元素可以通过行索引和列索引来访问。

1、二维数组的创建

我们知道,在 C 语言中,二维数组是一个连续的内存块,通常在声明时需要指定列数

  1. 列数必须确定:在编译时,列数必须是确定的,以便编译器能够正确计算每一行的偏移量。
  2. 行数可以不确定:行数可以在初始化时由编译器通过初始化的元素个数和列数推断出来。

但是 Java 的二维数组与 C 语言的数组是有很多区别的,我们后面也会讲到。

在 Java 中,二维数组实际上是一维数组的数组,这些子数组在内存上不一定连续。这意味着:

  1. 行数必须确定:当你创建一个二维数组时,你需要指定行数
  2. 列数可以不确定:每个子数组的元素个数可以单独分配,因此列数可以不同,甚至可以在之后动态分配。

也就是说你必须指出你要创建的子数组的个数(也就是行数),但是子数组的元素个数(也就是列数)不必指出,因为 Java 是支持二维数组子数组长度不同的。

1)列数确定动态创建

与一维数组一致,二维数组也要先声明一个数组引用变量:

int[][] arr;

然后使用 new 关键字创建一个数组对象,然后将数组对象的引用赋值给这个数组引用变量:

arr = new int[2][3];

这里就创建了一个二行三列的二维数组。

与一维数组一样,这两个操作也可以在一个语句中完成:

int[][] arr = new int[3][4];

这里就创建了一个三行四列的二维数组对象,然后将对象的引用赋值给前面的数组引用变量。

2)列数不确定的动态创建

int[][] arr = new int[3][];

这样就是创建了一个二维数组,二维数组的子数组是三个(也就是二维数组有三行),但是子数组的元素个数不确定(也就是列数不确定)。

在后面我们可以在对这个二维数组的每一个子数组进行单独的动态分配,这时就可以对不同的子数组分配不同的空间,这样不同的子数组就可以有不同个元素了。

int[][] arr = new int[3][];
arr[0] = new int[1];
//创建一个一维数组对象,这个数组对象只有一个int大小
//然后将这个数组的引用赋值给二维数组的子数组的引用变量,
//这个引用变量就是我们下面图解中说的那个专门用来存储子数组的引用的数组的元素,也就是arr[0]
//这个刚创建的数组就是这个二维数组的第一个子数组
arr[1] = new int[2];
//创建一个一维数组对象,这个数组对象只有二个int大小
//然后将这个数组的引用赋值给二维数组的子数组的引用变量arr[1]
//这个刚创建的数组就是这个二维数组的第二个子数组
arr[2] = new int[3];
//创建一个一维数组对象,这个数组对象只有三个int大小
//然后将这个数组的引用赋值给二维数组的子数组的引用变量arr[2]
//这个刚创建的数组就是这个二维数组的第三个子数组

这样最终的二维数组在内存中的存储情况就是:

可以发现这里的二维数组的三个子数组的长度是不一样的。

如果我们在声明了二维数组和其行数(或者说其子数组个数)后,没有对其子数组动态分配空间的话,那么对于原来存储子数组的引用的数组存储的元素都应当是 null。

也就是说当我们进行以下语句后:

int[][] arr = new int[3][];

arr 这个二维数组引用变量指向的用来存储其子数组的引用的数组的元素都应当是null,就像下面这样:

也就是说这时这个二维数组的子数组都还没有被创建。

arr[0] = new int[1];
arr[1] = new int[2];
arr[2] = new int[3];

然后我们依次进行二维数组的每个子数组的创建,然后每个子数组的引用依次存储到图中的这个数组中,然后二维数组引用变量 arr 就与其子数组有了联系。这个二维数组就形成了。

3)列数一样静态创建

与一维数组一致,二维数组也可以使用静态的方式创建:

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

这里就创建了一个三行三列的二维数组,然后将其元素都赋予特定的值。

4)列数不同静态创建

静态创建也可以使二维数组的每一个子数组的长度不同,只要每个内部的花括号中的元素个数不同就可以了。

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

这里这样初始化,这个二维数组就有三个子数组,第一个子数组有三个元素,第二个子数组有两个元素,第三个子数组有一个元素,这样也实现了子数组的长度不同,也就是列数不同。

对于静态初始化,如果子数组只有一个元素,花括号也不能省略,因为有了花括号才是一维数组类型,如果没有花括号就是整型了,类型不匹配,就像下面这样是错误的:

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

这里就会报错:

2、二维数组的访问与遍历

1)二维数组的访问

二维数组与一维数组的访问相似,只是多了一个下标,它需要两个下标。

int num = arr[0][0];

这就是访问二维数组 arr 的第一行的第一列的元素,然后赋值给整型变量 num。

2)遍历二维数组的每个元素

对于二维数组 arr,我们使用 .length 获取它的长度,获取的就是它的元素个数,但是对于二维数组,本质就是一维数组的数组,所以这里获取其元素个数就是获取其一维数组的个数,也就是其行数。然后我们使用 arr[i].length 就可以获取每一个二维数组的元素的长度,也就是每一行的元素个数,或者说是列数。

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

运行结果:

二、二维数组细节

1、二维数组的具体存储情况

这里我们使用以下二维数组作为例子来进行讲解:

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

下面我们进行详细讲解(这里每个元素被默认初始化为 0):

所以对于一个二维数组的创建,不只有二维数组的每个子数组在堆区中存储,还有一个一维数组用来存储每个子数组的引用。

这样做的原因是什么呢,我们下面来解释:

  • 支持锯齿状数组(也就是每个子数组的长度可以不同)

众所周知,在 C 语言中,二维数组的每个字数组的长度必须是一致的,而且 C 语言中二维数组的子数组的存储都是连续的。这样才能不需要一个单独的数组来存放子数组的地址就可以访问到所有子数组。

但是,在 Java 中,二维数组的子数组可以是不同的长度,这种设计允许非常灵活的数据结构,而不是强制所有行的长度都相同。而且 Java 的二维数组的子数组在内存上也不一定连续。例如下面这段代码:

int[][] jaggedArray = new int[3][];
jaggedArray[0] = new int[2];
jaggedArray[1] = new int[3];
jaggedArray[2] = new int[1];
{ {0, 0},
  {0, 0, 0},
  {0} }

但是同时也牺牲了内存,因为这样做要多出来一个一维数组用来存储子数组的引用,不然无法访问全部子数组。

  • 内存管理与效率

因为二维数组有一个专门存储每一个子数组的引用的数组,所以二维数组的每一行可以单独分配内存,这使得内存管理更加灵活。例如,在需要动态调整某一行的大小时,只需重新分配该行的内存,而不影响整个数组。

这种设计可以利用局部性原理。虽然二维数组的子数组的存储可能在内存中不完全连续,但是访问局部区域的数据可能更高效。因为有一个数组专门存储每一个子数组的引用。

  • 提高安全性

Java 提供数组边界检查,防止越界访问。每个子数组作为独立的对象,能更容易地进行边界检查,提高了程序的安全性。

  • 简化引用管理

每个数组都是独立的对象,由引用指向,这使得引用计数和垃圾回收更加简单和有效。当一个数组对象不再被引用时,JVM 可以回收其内存。

2、使用代码验证二维数组的存储

我们可以使用代码验证我们上面所提到的二维数组在内存中的存储情况。

public class Test {
	public static void main(String[] args) {
		int[][] arr = new int[2][3];
		System.out.println("二维数组引用变量arr中的引用为:" + arr);
		for(int i = 0; i < arr.length; i++) {
			System.out.println("二维数组用来存储子数组引用的数组的第" + (i + 1) + "个元素arr[" + i + "]为" + arr[i]);
		}
	}	
}

运行结果:

可以发现  arr 这个二维数组引用变量中存储的是用来存储子数组引用的数组的引用。然后就是用来存储子数组引用的数组的每个元素都是一个不同的子数组的引用,同时,我们还发现这两个子数组在内存中的存储明显不连续。

三、二维数组的使用实例与补充

1、遍历一个二维数组求其所有元素之和

public class Test {
	public static void main(String[] args) {
		int[][] arr = {{1, 2, 3}, {1, 2}, {1}};
		int sum = 0;
		for(int i = 0; i < arr.length; i++) {
			for(int j = 0; j < arr[i].length; j++) {
				sum += arr[i][j];
			}
		}
		System.out.println("sum = " + sum);
	}	
}

运行结果:

2、二维数组声明补充

二维数组的声明可以是以下三种方式:

//推荐方式
int[][] arr;
//C语言形式声明
int arr[][];
//
int[] arr[];

第三种声明更能体现二维数组是一维数组的数组。

3、使用二维数组打印杨辉三角

杨辉三角:

第 n 行有 n 项,每一行的第一个和最后一个数字都是 1,其他数字为其上面的两个数字之和。

public class Test {
	public static void main(String[] args) {
		int[][] arr = new int[10][];
		for(int i = 0; i < arr.length; i++) {
			arr[i] = new int[i + 1];
			for(int j = 0; j < arr[i].length; j++) {
				if(j == 0 || j == i) {
					arr[i][j] = 1;
				} else {
					arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
				}
			}
		}
		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();
		}
	}	
}

运行结果:

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

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】使用pip安装seaborn sns及失败解决方法与sns.load_dataset(“tips“)

&#x1f60e; 作者介绍&#xff1a;我是程序员洲洲&#xff0c;一个热爱写作的非著名程序员。CSDN全栈优质领域创作者、华为云博客社区云享专家、阿里云博客社区专家博主。 &#x1f913; 同时欢迎大家关注其他专栏&#xff0c;我将分享Web前后端开发、人工智能、机器学习、深…

RISC-V MCU IDE MRS(MounRiver Studio)开发 编译后打印FLASH及RAM使用占比信息

以RISC-V MCU IDE MounRiver Studio(MRS)为例&#xff0c;首先我们选中目标工程&#xff0c;点击工具栏工程属性按钮&#xff0c;打开工程属性配置页&#xff1a; 在C/C Build->Settings->Tool Settings选项列表中单击GNU RISC-V Cross C Linker->Miscellaneous&#…

Anzo 跟单社区现已正式上线!即刻体验无与伦比的强大功能

Anzo 跟单社区现已正式上线! ANZO 跟单社区是一个颠覆性的创新跟单社区平台&#xff0c;作为新一代跟单社区&#xff0c;我们旨在让更多的用户享受跟单交易带来的便捷性和收益性。交易者可以通过跟单社区&#xff0c;学习和分享交易策略&#xff0c;轻松复制交易专家的交易策略…

人类记忆优化算法:针对全局优化问题的记忆启发优化器

Human memory optimization algorithm: A memory-inspired optimizer for global optimization problems 24年 Expert Systems With Applications sci一区 原文链接: https://doi.org/10.1016/j.eswa.2023.121597 Zhu D, Wang S, Zhou C, et al. Human memory optimization alg…

二进制文件的膨胀策略和使用 debloat 消除膨胀测试

在恶意软件的分析中有的 Windows 可执行文件&#xff08;PE 文件&#xff09;会通过膨胀策略来绕过防病毒一些防病毒的检查&#xff0c;比如上传云进行分析&#xff0c;因为文件太大了所以无法进行一些防病毒分析。一般的可执行文件有很多的膨胀策略&#xff0c;一般简单的膨胀…

Elasticsearch-经纬度查询(8.x)

目录 一、开发环境 二、pom文件 三、ES配置文件 四、ES相关字段 五、ES半径查询 ES的字段类型:geo_point&#xff0c;可以实现以一个点为中心的半径查询(geo_distance query) ES 地里位置查询: 半径查询(geo_distance query)查询指定矩形内的数据(geo_bounding_box quer…

[AI Google] 使用 Gemini 取得更多成就:试用 1.5 Pro 和更多智能功能

总结 Google 正在为超过 35 种语言的 Gemini Advanced 订阅者推出 Gemini 1.5 Pro。此次更新包括 100 万个 token 的上下文窗口、改进的数据分析功能和增强的多模态图像理解。新功能包括用于自然对话的 Gemini Live、先进的规划工具和可定制的 Gems。更新还集成了更多 Google …

基于STM32开发的智能农业监控系统

目录 引言环境准备智能农业监控系统基础代码实现&#xff1a;实现智能农业监控系统 4.1 土壤湿度传感器数据读取4.2 温湿度传感器数据读取4.3 水泵与风扇控制4.4 用户界面与数据可视化应用场景&#xff1a;农业环境监测与管理问题解决方案与优化收尾与总结 1. 引言 随着智能…

SkyWalking之P0核心业务场景输出调用链路应用

延伸扩展&#xff1a;XX核心业务场景 路由标签打标、传播、检索 链路标签染色与传播 SW: SkyWalking的简写 用户请求携带HTTP头信息X-sw8-correlation “X-sw8-correlation: key1value1,key2value2,key3value3” 网关侧读取解析HTTP头信息X-sw8-correlation&#xff0c;然后通过…

Navicat导入json文件(json文件数据导入到MySQL表中)

天行健&#xff0c;君子以自强不息&#xff1b;地势坤&#xff0c;君子以厚德载物。 每个人都有惰性&#xff0c;但不断学习是好好生活的根本&#xff0c;共勉&#xff01; 文章均为学习整理笔记&#xff0c;分享记录为主&#xff0c;如有错误请指正&#xff0c;共同学习进步。…

在Modelarts上微调量化Llama3,并用docker部署

本文概述 本文先使用llama-factory去微调llama3大模型&#xff0c;然后使用llama.cpp去量化模型并打包为docker部署到服务器上让qq机器人能够调用服务&#xff0c;实现qq群内问答。 效果展示 环境准备 本文使用华为云的Modelarts的notebook去进行的模型微调 ubuntu20.04&#x…

揭开FFT时域加窗的奥秘

FFT – Spectral Leakage 假设用于ADC输出数据分析的采样点数为N&#xff0c;而采样率为Fs&#xff0c;那我们就知道&#xff0c;这种情况下的FFT频谱分辨率为δf&#xff0c;那么δfFs/N。如果此时我们给ADC输入一个待测量的单频Fin&#xff0c;如果此时Fin除以δf不是整数&a…

IP地址冲突检测(Address Conflict Detect)记录

学习目标&#xff1a; 提示&#xff1a;ACD(IP地址冲突检测)原理学习与抓包分析 学习记录&#xff1a; 1、Address Conflict Detection地址冲突检测&#xff0c;简称ACD。RFC 5227提出ACD机制。其中ACD将arp request分为ARP probe和ARP announcement两种&#xff1b; ACD定义…

数据中心网络运维探讨

数据中心网络运维探讨 数据中心网络运维通过科学的网络架构设计、实时监控管理、智能化运维工具和全面的安全防护&#xff0c;确保网络的高效、安全运行。它不仅提升了运维效率和网络可靠性&#xff0c;还保障了业务的连续性和数据安全。随着技术的不断进步&#xff0c;智能化…

常见机器学习的原理及优略势

有监督 一、线性回归&#xff08;Linear Regression) 1. 算法原理 线性回归&#xff08;Linear Regression&#xff09;是一种基本的回归算法&#xff0c;它通过拟合一个线性模型来预测连续型目标变量。线性回归模型的基本形式是&#xff1a;y w1 * x1 w2 * x2 … wn * …

在python中关于元组的操作

创建元组 如上图所示&#xff0c;a&#xff08;&#xff09;和b tuple(),,这两种方式都可以创建出元组。 在创建元组的时候&#xff0c;指定初始值 如上图所示&#xff0c;也可以在创建元组的时候&#xff0c;指定初始值。 同列表一样元组中的元素也可以是任意类型的。 同列…

Map深度学习

Map Map是一个键值对的集合&#xff0c;和object类似&#xff0c;Map作为构造函数&#xff0c;可以通过全局对象获取到。需要通过new操作创建实例对象&#xff0c;直接调用会报错。Map构造函数接受一个iterable类型的函数&#xff0c;用来初始化Map。 var m new Map([[1, &qu…

pyrouge(ROUGE-1.5.5)的安装步骤和使用说明(适用于Linux 系统)

摘要&#xff1a;本文讲解了如何配置和使用文本摘要的评价指标ROUGE(linux 系统)。 ✅ NLP 研 1 选手的学习笔记 简介&#xff1a;小王&#xff0c;NPU&#xff0c;2023级&#xff0c;计算机技术 研究方向&#xff1a;摘要生成、大语言模型生成 文章目录 一、为啥要写这篇博客&…

Redis 双写一致原理篇

前言 我们都知道,redis一般的作用是顶在mysql前面做一个"带刀侍卫"的角色,可以缓解mysql的服务压力,但是我们如何保证数据库的数据和redis缓存中的数据的双写一致呢,我们这里先说一遍流程,然后以流程为切入点来谈谈redis和mysql的双写一致性是如何保证的吧 流程 首先…

flink源码系列:RPC通信

这里写目录标题 1. 本节课目的2.开始本节内容2.1.RPC概念3.2.大数据组件常见的RPC实现技术3.3.Pekko&#xff08;Akka&#xff09;3.3.1. Akka、Pekko基本概念3.3.2.Pekko Demo事例3.3.2.1.PekkoData 类3.3.2.2.PekkoRpcReceiverActor类3.3.2.3.PekkoRpcSenderActor 类3.3.2.4.…