这次给大家介绍一下数组的定义和应用。废话不多说,正文开始!
一、 数组的基本用法
1.什么是数组
数组本质上允许我们“批量”创建相同类型的变量。
例如:
如果需要表示两个数据,那么直接创建两个变量为int a;诠释 b
如果需要表示五个数据,可以创建五个变量 int a1;诠释a2;诠释a3;诠释a4;诠释a5;
但是如果你需要表示 10,000 个数据,那么你就不能创建 10,000 个变量。这时候就需要使用数组来帮助我们批量创建。
上面是一个整数数组。
注意:在 Java 中,数组中包含的变量必须是同一类型。
2. 创建数组
基本语法
在上面的例子中,我们以整数数组为例,创建一个int[]类型的数组数组,存储5个整数数据。解释了数组创建的用法。Java 数组的创建与 C 语言非常相似。相似,但有区别。
C语言版本数组创建:
Java版本数组创建:
我们可以看到两种写作方式之间的区别。在 Java 中,[ ] 必须位于数据类型旁边。
数组的数据连续存储在内存中。继续以上面的代码为例:
数组的每个元素都有对应的下标,下标->从0开始。如果我们想在这个数组中找到某个数据,我们通过数组的下标来访问它。
注意:数组也称为集合,包含一组相同类型的数据!!下标从位置 0 开始。
3.如何定义一个数组
定义方法一
我们上面写的代码是定义和初始化一个数组。
这种方式只定义了一个数组。这是我们定义数组的第一种方式。而这种方式定义的数组的默认大小是0.
定义 2
这里也定义了一个数组,但是这个数组定义使用了new等关键字为数组分配了一块内存,而这块内存有10条数据可以存储。
int[10] 分配的连续内存空间。
不过此时我们还没有初始化数组数组,所以此时数组的十个数据的默认值为0.
定义三
在Java中,初始化后=左边的[]不能填数字,而=右边的[]只能在第二个定义中赋值。
在定义模式三
总结一下定义数组的三种方式:
在这三种方式中,Java 中定义数组最常见的方式是方式一。
4. 数组的使用
(1)获取长度
预防措施
使用 arr。获取数组的长度。这个操作是成员访问操作符,后面会在面向对象中经常用到。
代码示例:
编译结果:
(2)访问数组中的元素
数组访问方法:
预防措施:
1.使用 [ ] 按下可索引数组元素。需要注意的是下标从0开始计数
2.使用 [ ] 操作来读取和修改数据。
3.下标访问操作不能超出有效范围[0, ),如果超出有效范围会出现下标越界异常
代码示例:
编译结果:
(3)下标越界
数组下标从0开始,范围为[0, arr.),左闭右开区间,或[0, arr.-1]。
如果我们将下标的值放在数组的边界之外……
如下
编译结果:
(4) 遍历数组
所谓“遍历”,是指访问数组中的所有元素一次,不再重复。通常需要与循环语句匹配
1. 遍历方法(一)—–for循环
编译结果:
我们可以看到,for循环是用来一个一个遍历数组中的元素,并打印出来的。
2.遍历方法(二)—->for-each
for-each 是使用 for 循环的另一种方式。可以更方便的完成数组的遍历。它可以避免错误地编写循环条件和更新语句。
for-each 的基本使用
代码示例:
编译结果:
for-each遍历原理
遍历数组中的每个元素,取出每个元素,赋值给x,最后打印x,直到遍历完数组中的所有元素。
我们已经介绍了两种遍历方式,那么for循环和for-each有什么区别呢?
for循环可以获取数组下标,而for-each无法获取数组下标,所以for-each只能遍历所有c语言字符数组逆序输出,不能修改或操作数组元素。
3. 遍历方法(三) – 使用操作数组的工具类打印数组
它是一个用于操作 Java 数组的工具类。如果你想对数组做一些事情,你可以通过它来做。当然,有些事情是他做不到的。
例如:我们要打印一个数组,我们原本是用for循环或者for-each写的,但是我们也可以使用类来打印。
通过JDK的工具文档,我们找到了对应的工具类。
好吧,我们对 arr 数组进行如下操作:
编辑结果:
5.在内存中存储数组
我们在上一篇博客中已经简单介绍了Java中内存区域的划分,那么今天我们知道了数组的引用类型,那么它是如何存储在内存中的呢?
下面简单回顾一下Java的内存区域
我们知道,局部变量存放在Java虚拟机栈上,而数组的数据存放在堆上。数组的数据在堆上有一个特定的地址,而数组的变量其实就是这组数据的地址。栈上的这个变量根据这个地址找到堆上的数据。
数组的具体存储如下图所示:
当心:
上图是arr所指向的数据在堆中的地址。这个地址不是真实地址,是通过官方地址哈希得到的。但是我们可以把它当作真正的地址,因为这个地址也是唯一的。
那么为什么要对真实地址进行哈希处理呢?
这就是Java的安全性,它不会轻易暴露自己数据的地址。
二、数组作为方法参数
1.基本用法
代码示例:打印数组内容
在这段代码中
1.int [ ] a 是函数的形参,int [ ] arr 是函数实参。
2.如果需要获取数组的长度c语言字符数组逆序输出,也可以使用a.
2.理解引用类型
在上一篇博客Using 中,我们介绍了一个使用方法交换两个变量的具体案例。现在让我们回顾一下。
(1) 参数传递内置类型
我们使用内置类型作为参数来交换变量,但是最终编译的结果是两个变量没有交换。
为什么是这样?
交换形参的值而不影响实参的值。
(2)参数传递数组类型
我们使用数组作为参数来交换变量。编译运行后,我们发现两个变量的值交换成功了。此时,数组名 arr 是一个“引用”。传递参数时,参数是通过引用传递的。
那么为什么引用传递类型可以对形参和实参进行操作呢?
在这里,我们必须从记忆开始。上面我们介绍了数组在内存中的存储。
我们可以知道,存储在栈中的数组变量实际上存储了堆中数据的地址。当我们将 arr 数组作为参数传递给方法时,我们传入的是堆中数据的地址。在方法内部,我们可以根据这个地址找到堆中的数据,然后修改数据,从而实现形参改变实参的操作。
总结:
所谓的“引用”本质上只是存储了一个地址。Java将数组设置为引用类型,这样数组参数的后续传参只传入数组的地址到函数参数中。这样就避免了对整个数组Copy的需要(数组可能很长,所以复制的代价会很大)。
3.识别空
引用类型的值为 0 为空。
当我们将 null 分配给引用类型 arr 时,这意味着什么?
表示引用 arr,它不指向任何对象。
当我们运行这段代码时,显示的结果是空的,而不是一个值0.
那么我们再来看看另一个问题。当我们将 null 分配给 arr 时,arr 数组的长度是多少?
我们猜测它可能是 0,现在让我们运行代码。
结果如下:
此时编辑器报错,错误类型:空指针异常。
嗯,这时候我们就可以知道给arr赋值了null,arr没有指向任何数组对象,也没有在堆上开辟内存空间,所以找不到它的长度。
总结:
空值。任何事情,都会发生空指针异常错误。
经验:以后只要出现这样的异常,肯定是这个引用为空。
4.JVM内存区域划分介绍
一个宿舍楼将分为几个不同的区域:大一学生、大二学生……计算机专业、通信专业……
记忆也是类似的。这条大走廊被分成许多部分,每个区域存储着不同的数据。
JVM的内存分为几个区域,如图:
程序计数器(PC):
只是一个小空间,保存下一条要执行的指令的地址。
虚拟机堆栈(JVM 堆栈):
关键是存储局部变量表(当然还有其他信息)。我们刚刚创建的int[] arr之类的存储地址的引用就存储在这里。
本机方法栈(Stack)
本机方法堆栈类似于虚拟机堆栈。唯一保存的是方法的局部变量。在某些版本的 JVM 实现中(例如),本机方法堆栈和虚拟机堆栈是在一起的。
堆:
JVM 管理的最大内存区域。用 new 创建的对象保存在堆上(比如之前的 new int[]{1, 2, 3} )
方法区(Area):
用于存储类信息、常量、静态变量、实时编译器编译的代码等数据已经被虚拟机加载。方法编译的字节码存放在这个区域。
运行时常量池(Pool):
它是方法区的一部分,存储文字(字符串常量)和符号引用。(注意从JDK1.7开始,运行时常量池在堆上)
关于上面的划分方法,后面我们会慢慢了解。这里我们重点了解虚拟机栈和堆。
1.局部变量和引用存放在栈上,新对象存放在堆上。
2.堆空间很大,栈空间比较小。
3.堆是整个JVM共享的,每个线程都有一个栈(一个Java程序中可能有多个栈)。
三、数组作为方法的返回值
代码示例:
此代码可行,但破坏了原始数组。有时我们不想破坏原来的数组,需要在方法内部新建一个数组,并有方法返回。
修改后的代码:
这样,原始数组就不会被破坏。
另外,由于数组是引用类型,所以返回时只返回数组的首地址给函数调用者,不复制数组的内容,效率更高。
四、数组练习
1.数组转字符串
题目要求:
实现一种将整数数组转换为字符串的方法。
例如数组 {1, 2, 3} ,返回字符串为“[1, 2, 3]”,注意逗号的位置和个数。
2.数组复制
数组复制方法
1.for 循环复制
在这个拷贝方法中,我们首先通过new拷贝一个与arr长度相同的新数组,然后通过for循环将arr数组的内容一一赋值给拷贝数组,达到最终数组拷贝的效果。
2.数组的工具类
1)()
我们先通过JKD的工具文档看一下复制工具的使用方法
功能:复制指定的数组,截断或用零填充(如果需要),使副本具有指定的长度。
下面我们来看看Java中方法的具体实现
首先.()的返回类型是int[],第一个参数是原数组(要复制的数组),第二个参数是新数组的长度(可以自己设置),如果新数组的长度比原数组长,如果长,大于原数组长度的元素用0填充。具体如下……
(2)()
我们先通过JDK文档看一下这个工具类的功能
功能:将指定数组的指定范围复制到一个新数组中。
下面我们来看看Java中方法的具体实现
该方法的返回类型是 int [ ] ,第一个参数是原始数组,第三个参数二、是要复制的原始数组数据的下标。一定要记住,它是一个左闭右开的区间,[ from , to )。
代码示例
3.。
我们打开方法的具体实现,发现并没有上述复制方法的实现过程。如上一节所述,这是一种本地方法。
本机方法
1. 在本机方法堆栈上运行
2.底层由C/C++代码实现
. 没有返回值,第一个参数是原数组(要复制的数组),第二个参数是要复制的原数组的下标,第三个参数是目标数组,第四个参数是下标目标数组。index,第五个数组是要复制的长度。
代码示例:
当心:
. 最后一个参数——要复制的数组长度,这个数据不能超过原数组的长度,否则编辑器会报错:数组越界。
4..clone —-> 生成当前数组的副本
功能:生成当前数组的副本。
代码示例:
3. 查找数组中最大的元素
题目内容:给定一个整数数组,求其中最大的元素(类似于求最小元素)
代码:
4. 求数组中元素的平均值
主题内容
给定一个整数数组,求平均值
代码:
当心:
最后,在aver方法中计算平均值的时候,记得sum * 1.0,这样计算出来的平均值就是数据的类型。
5.在数组中查找指定元素(顺序查找)
主题内容
给定一个数组,并给定一个元素,找出该元素在数组中的位置。
代码
6.在数组中查找指定元素(二分查找)
对于已排序的数组,可以使用更有效的二分查找。
什么是有序数组?
顺序分为“升序”和“降序”,如1 2 3 4,为升序。例如4 3 2 1,降序为降序。
以升序数组为例,二分查找的思路是先取中间位置的元素,看要查找的值是大于还是小于中间元素。小的话往左边找;否则,去右边找到它。
代码:
二分查找的具体思路可以看我之前的博客——在有序数组中查找特定的数n(二分查找)了解详情。
7.检查数组的顺序
主题内容
给定一个整数数组,判断该数组是否排序(升序)
代码:
当心:
记得检查传入的数组是否为null,如果传入的arr数组为null,则返回false类型。
8.数组排序(冒泡排序)
主题内容
给定一个数组,按升序(降序)对数组进行排序。
算法思路
每次尝试在要排序的当前范围内查找最小(或最大)元素时,将其放在数组的前面(或后面)。
代码:
关于冒泡排序的详细解释可以看我之前的博客——排序算法的冒泡排序,这里就不过多介绍了。
9.数组倒序
主题内容
给定一个数组,以相反的顺序对元素进行排序。
想法
设置两个下标,分别指向第一个元素和最后一个元素。交换两个位置的元素。
然后让前一个下标自动递增,后一个下标递减,循环可以继续。
代码:
五、二维数组
二维数组本质上是一维数组,只是每个元素都是一维数组。
正则二维数组
(1)二维数组的定义
(2)内存中的二维数组
以上面的 int[2][3] 为例
前面我们说过,二维数组本质上是一个特殊的一维数组。
这个数组的每一行arr[0]和arr[1]构成一个一维数组,每一行存储指向每一列数据的地址。
每列也是一个单独的一维数组,指向堆中的每一条数据。
(3) 打印二维数组
知道了二维数组在内存中的存储和指向,我们就知道了arr。获取行数和 arr [ i ]。获取列数。
for循环打印
我们在 for 循环中打印这个二维数据。
代码示例:
@>
打印结果:
2.for-each 打印
如果我们使用 for-each 打印,代码示例:
打印结果如下:
3. 工具类打印
在一个一维数组中,我们希望将数组转换为一个字符串来打印。( )。那么二维数组转字符串的工具类是什么?
如果我们用 . ( )
结果打印出由 arr 行表示的数组的内容——由该列表示的一维数组的地址。明显地。( ) 不能打印二维数组的全部内容。
我们查阅了 JDK 文档并找到了 ( ) 实用程序类。
功能:返回指定数组的“深层内容”的字符串表示形式。
我们使用 () 来打印…
结果如下:
二维数组的内容打印成功。
( ) 可以正确打印出二维数组的所有数据。
不规则二维数组
在C语言中,我们定义一个二维数组只能定义列,而不指定行的值。
C语言中数组的定义
在Java中,我们只能定义行,列不需要指定值。
Java中不规则二维数组的定义
什么是不规则二维数组?
在前面规则的二维数组中,每一行的数据数和列数都是一样的。不规则的二维数组指定行数,列数自己确定,每行的列数自己确定。
(1)不规则二维数组的定义
编译结果:
首先我们指定一个有两行的二维数组
int [ ] [ ] arr = 新的 int [2] [ ];
我们自己指定数组的每一行有多少列。
arr[ 0 ] = 新的 int [ ] { 1,2,3 }
arr [ 1 ] = 新 int [ ] { 4,5 };
这是不规则二维数组的定义。
(2)内存中的二维数组
与常规的二维数组内存存储基本相同。
(3) 方式
同样,还有“三维数组”、“四维数组”等更复杂的数组,但出现的频率很低。
今天的分享已经结束,请多多包涵,指点!
文章来源:http://www.toutiao.com/a6953962692805853709/
感谢您的来访,获取更多精彩文章请收藏本站。

暂无评论内容