首页 > 编程语言 >Java——二维数组

Java——二维数组

时间:2024-06-09 10:04:09浏览次数:19  
标签:arr Java int 二维 引用 数组 new

一、二维数组介绍

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

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();
		}
	}	
}

运行结果:

标签:arr,Java,int,二维,引用,数组,new
From: https://blog.csdn.net/stewie6/article/details/139547530

相关文章

  • 2024050801-重学 Java 设计模式《实战策略模式》
    重学Java设计模式:实战策略模式「模拟多种营销类型优惠券,折扣金额计算策略场景」一、前言文无第一,武无第二不同方向但同样努力的人,都有自身的价值和亮点,也都是可以互相学习的。不要太过于用自己手里的矛去攻击别人的盾......
  • 【java问答小知识3】一些Java基础的知识,用于想学习Java的小伙伴们建立一些简单的认知
    什么是Java的Lambda表达式?回答:Lambda表达式是Java8引入的一种语法糖,允许你以简洁的格式编写匿名函数。什么是Java的StreamAPI?回答:StreamAPI是Java8引入的,提供了一种声明式处理集合数据的方式,支持并行处理。什么是Java的Optional类?回答:Optional是一个容器对象,......
  • JAVA计算机毕业设计基于的旅游景区指南系统的设计与实现(附源码+springboot+开题+论文)
    本系统(程序+源码)带文档lw万字以上 文末可获取一份本项目的java源码和数据库参考。系统程序文件列表开题报告内容研究背景随着信息技术的飞速发展,旅游业也迎来了数字化转型的浪潮。旅游景区作为旅游业的重要组成部分,其管理和服务方式正逐渐从传统的模式向智能化、个性化转......
  • JavaScript 语法 随记(打印语句)
    JavaScript语法随记(打印语句)window.alert("Hello,World!-----1"),//弹出框 内显示内容document.write("Hello,World!-----2");//在新开网页上面显示内容console.log("Hello,World!--------3");//在控制台显示  (常用)console.error("Hello,World!-......
  • Java Tool - java 命令
    参考资料官网文档-https://docs.oracle.com/javase/8/docs/technotes/tools/unix/java.htmljava命令用于启动1个Java应用,即启动一个JVM进程。1语法java [_options_] _classname_ [_args_]java [_options_] -jar_filename_ [_args_]options-空格分......
  • C语言学习笔记(八)————数组
    提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档文章目录前言1一维数组1.2一维数组的引用1.3一维数组的初始化2二维数组2.1二维数组的定义2.2二维数组的存放顺序3多维数组总结前言一个学习C语言的小白,有问题评论或私信~本文主要记录C语言......
  • 从零手写实现 nginx-01-为什么不能有 java 版本的 nginx?
    前言大家好,我是老马。很高兴遇到你。作为一个java开发者,工作中一直在使用nginx。却发现一直停留在使用层面,无法深入理解。有一天我在想,为什么不能有一个java版本的nginx呢?一者是理解nginx的设计灵魂,再者java开发者用java语言的服务器不是更加自然吗。于是......
  • 代码随想录算法训练营 day31 | 455.分发饼干 376.摆动序列 53.最大子数组和
    376.摆动序列说实话,没明白为啥算是贪心。最开始的思路是去重,然后统计正负变化次数。classSolution{public:intwiggleMaxLength(vector<int>&nums){if(nums.size()==1)return1;intans=0,last=-2,now;for(inti=1;i<nums.size();......
  • JavaScript:从基础到进阶的全面介绍
    JavaScript:从基础到进阶的全面介绍JavaScript(简称JS)是一种广泛用于Web开发的编程语言。它是一种轻量级的、解释型或即时编译的语言,具有函数优先的特点。JS最初是为了实现网页的动态效果而设计的,如今已发展成为前端开发、服务器端开发、移动开发等多个领域的重要工具。本文......
  • JavaWeb中,web应用的上下文路径解读
    当前Web应用的上下文路径(ContextPath)指的是Web应用在服务器上的根路径。在Servlet或JSP环境中,一个服务器可以运行多个Web应用,每个应用都有一个唯一的上下文路径。例如,如果你的Web应用部署在Tomcat服务器上,并且在Tomcat的webapps目录下有一个名为myapp的Web应用,那么这个应......