您的位置 首页 java

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

今日分享开始啦,请大家多多指教~

本次给大家介绍数组的定义与应用,话不多说,正文开始啦!

一、 数组基本用法

1.什么是数组

数组本质上就是让我们能 “批量” 创建相同类型的变量.

例如:

如果需要表示两个数据, 那么直接创建两个变量即可 int a; int b

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

如果需要表示五个数据, 那么可以创建五个变量 int a1; int a2; int a3; int a4; int a5;

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

但是如果需要表示一万个数据, 那么就不能创建一万个变量了. 这时候就需要使用数组, 帮我们批量创建.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

上面就是整型数组.

注意事项: 在 Java 中, 数组中包含的变量必须是相同类型.

2. 创建数组

基本语法

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

在上面的实例中,我们就以整型数组为例,创建了一个 int [ ] 类型的array数组,并且存放了5个整形数据.讲解了数组创建时的用法,Java数组的创建与C语言很是相似,但是还是有区别的.

C语言版本数组的创建:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

Java版本数组的创建:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们可以通过两种写法看到其中的区别. Java当中一定要 [ ] 和数据类型紧挨在一起.

数组的数据在内存中是连续存放的.继续以上面的代码为例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

数组的每一元素都有其对应的下标,而下标->从0开始,我们要想找到这个数组中的某个数据,是通过数组的下标来进行访问的.

注意: 数组也被称为存放一组相同类型的数据的集合!!下标是从0号位置开始的.

3.定义数组的方式

定义方式一

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

上面我们写的代码是,定义并初始化了一个数组.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

这样的方式才只是定义了一个数组.这就是我们定义数组的第一种方式.且这样定义的数组默认大小为0.

定义方式二

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

这样也是定义了一个数组,不过这个数组定义是通过new 这样一个关键字,给 array 分配了一块内存,这块内存有10个数据可以存放.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

int [ 10 ] 分配的连续内存空间.

不过此时,我们还未给 array 这个数组进行初始化,所以 array 此时的这十个数据默认值为0.

定义方式三

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

在Java当中在已经初始化之后, = 左边的 [ ] 中是不能填数字的, = 右边的 [ ] 只有在 定义方式二 中可以给定值.

在定义方式三中

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

总结定义数组的三种方式:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

在这三种方式中,Java中定义数组最常用的是方式一。

4. 数组的使用

(1)获取长度

注意事项

  1. 使用 arr.length 能够获取到数组的长度, 这个操作为成员访问操作符,后面在面向对象中会经常用到。

代码示例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

编译结果:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

(2)访问数组中的元素

数组访问的方式:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

注意事项:

1.使用 [ ] 按下标取数组元素. 需要注意, 下标从 0 开始计数

2.使用 [ ] 操作既能读取数据, 也能修改数据.

3.下标访问操作不能超出有效范围 [0, length) , 如果超出有效范围, 会出现下标越界异常

代码示例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

编译结果:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

(3)下标越界

  数组下标从0开始,范围是 [0,arr.length) ,左闭右开的区间,或者是[ 0,arr.length-1].

  如果我们将下标的值超出数组的范围…

如下所示

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

编译结果:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

(4)遍历数组

  所谓 “遍历” 是指将数组中的所有元素都访问一遍, 不重不漏. 通常需要搭配循环语句

1.遍历方式(一)—–for循环

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

编译结果:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们可以看到,用 for 循环 将数组中的元素一 一遍历 并打印出来.

2.遍历方式(二)—->for-each

for-each 是 for 循环的另外一种使用方式. 能够更方便地完成对数组的遍历. 可以避免循环条件和更新语句写错.

for-each 的基本使用

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

代码示例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

编译结果:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

for-each 遍历的原理

遍历array 里面的每一个元素,把每一个元素取出来,然后赋值给了 x ,最后打印 x ,直到 array 里面的元素全部都遍历完成.

两种遍历的方式我们介绍完了,那么for循环和for-each有什么区别?

for循环 是可以拿到数组下标的,for-each拿不到数组下标,所以for-each只能够全部遍历,无法对数组元素进行修改或进行操作.

3.遍历方式(三)——使用操作数组的工具类进行数组的打印

Arrays 就是操作Java数组的工具类,你要对数组做什么事情,就可以通过他来做,当然有些事情他是完成不了的.

比如说:我们要打印数组,我们本来是用for循环 或者 for-each 来写的,但是我们也可以用Arrays的工具类打印.

通过 JDK 的工具文档,我们查找到了相应的工具类.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

好,我们对arr数组进行操作如下:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

编辑结果:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

5.数组在内存中的存储

我们在之前的博客已经很简单介绍了Java中的内存区域划分,那么今天我们认识了数组这个引用类型,那么它在内存中如何进行存储呢?

我们先简单回顾一下Java的内存区域

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们知道局部变量都在 Java虚拟机 栈上存放,而数组的数据则在堆上进行存放, 数组的数据在堆上都有特定的地址,而数组的变量存放的其实是这组数据的地址,栈上的这个变量根据这个地址找到堆上的数据.

数组的具体存储由下图所示:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

注意点:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

上图为arr指向的数据在堆中的地址,这个地址并不是真正的地址,它是通过正式的 地址 hash 得到的.但是我们可以把它当作真实的地址,因为这个地址也是唯一的.

那么真实的地址为什么要hash操作呢?

这就是Java的安全性了,不会轻易暴露自己数据的地址.

二、数组作为方法的参数

1.基本用法

代码示例: 打印数组内容

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

在这个代码中

1.int [ ] a 是函数的形参, int [ ] arr 是函数实参.

2.如果需要获取到数组长度, 同样可以使用 a.length

2.理解引用类型

在上一期博客 方法的使用中 ,我们介绍了一个用方法来交换两个变量 的具体情况.现在我们来回顾一下.

(1)参数传内置类型

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们用 内置类型作为参数,进行交换变量,但是最后编译的结果 两个变量却并未发生交换.

这是为什么呢?

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

交换形参的值, 不影响实参的值.

(2)参数传数组类型

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们用 数组作为参数,进行交换变量,编译运行后,发现成功交换两个变量的值。此时数组名 arr 是一个 “引用” . 当传参的时候, 是按照引用传参.

那么为什么传引用类型可以 形参可对实参进行操作呢?

这里我们就要先从内存说起,在上面我们介绍了数组在内存中的储存

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们可以知道,数组这个在栈中存放的变量实际存放的是 堆中数据的地址,当我们 arr 数组作为参数 传入 方法里,我们就把 堆中数据的地址 传入了进去,在方法内部,我们可以根据 这个地址 找到堆中的数据进而修改数据,从而实现了 形参 改变了实参的操作。

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

总结:

3.认识 null
引用类型的0值 就是 null.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

当我们将 null 赋给arr 这个引用类型时,这又是什么意思呢?

代表 arr 这个引用,不指向任何对象.
当我们运行这个代码时,显示的结果就是 null ,不是数值 0.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

那我们再来看一个问题,当我们将 null 赋给 arr 之后,那么arr 数组的长度是多少呢?

我们猜测可能为0,现在来运行代码.

运行结果如下:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

此时,编辑器报错,错误类型:空指针异常.

好了,这时我们可以知道,null 赋给了 arr ,arr 没有指向任何一个数组对象,在堆上也没有开辟内存空间,所以我们也就无法求它的长度.

总结:

null.任何东西,都会发生 空指针异常的错误.

经验:只要以后出现这样的异常,肯定是这一个引用是 null.

4.初识 JVM 内存区域划分

一个宿舍楼会划分成几个不同的区域: 大一学生, 大二学生… 计算机专业学生, 通信专业学生…

内存也是类似, 这个大走廊被分成很多部分, 每个区域存放不同的数据.

JVM 的内存被划分成了几个区域, 如图所示:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

程序计数器 (PC Register):

只是一个很小的空间, 保存下一条执行的指令的地址.

虚拟机 栈(JVM Stack):

重点是存储局部变量表(当然也有其他信息). 我们刚才创建的 int[] arr 这样的存储地址的引用就是在这里保存.

本地方法栈(Native Method Stack)

本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的.

堆(Heap):

JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} )

方法区(Method Area):

用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域.

运行时常量池(Runtime Constant Pool):

是方法区的一部分, 存放字面量(字符串常量)与符号引用. (注意 从JDK1.7 开始, 运行时常量池在堆上)

关于上面的划分方式, 我们随着后面的学习慢慢理解. 此处我们重点理解 虚拟机栈 和 堆.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

1.局部变量和引用保存在栈上, new 出的对象保存在堆上.

2.堆的空间非常大, 栈的空间比较小.

3.堆是整个 JVM 共享一个, 而栈每个线程具有一份(一个 Java 程序中可能存在多个栈).

三、数组作为方法的返回值

代码示例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

这个代码固然可行, 但是破坏了原有数组. 有时候我们不希望破坏原数组, 就需要在方法内部创建一个新的数组, 并有方法返回出来。

修改后的代码:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

这样的话就不会破坏原有数组了.

另外由于数组是引用类型, 返回的时候只是将这个数组的首地址返回给函数调用者, 没有拷贝数组内容, 从而比较高效。

四、数组练习

1.数组转字符串

题目要求:

实现一个方法 toString, 把一个整型数组转换成字符串.

例如数组 {1, 2, 3} , 返回的字符串为 “[1, 2, 3]”, 注意 逗号 的位置和数量.

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

2.数组拷贝

数组的拷贝方式

1.for循环拷贝

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

在这种拷贝方式中,我们首先通过 new 一个新的和 arr 一样长度数组 copy ,再通过 for 循环将 arr 数组中的内容 一 一赋给copy数组,达到 最终的数组拷贝的效果.

2.Arrays数组的工具类

1)copyOf()

我们先通过JKD的工具文档,来看一下拷贝工具的用法

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

功能:复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度.

具体看一下Java当中copyOf方法的具体实现

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

首先 Arrays.copyOf() 的返回类型是 int [ ] ,第一个参数是 原数组(要拷贝的数组),第二个参数是新数组的长度(可以自己定),如果新的数组的长度比原数组长的话,大于原数组长度的元素都补为0 。 具体如下所示…

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

(2)copyOfRange()

我们先通过JDK文档来查看这个工具类的功能

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

功能:将指定数组的指定范围复制到新的数组中.

具体看一下Java当中copyof方法的具体实现

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

copyOfRange 方法的返回类型是 int [ ] ,第一个参数是 原数组 ,第二、三参数是要拷贝原数组数据的下标 ,一定要切记 是左闭右开的区间 , [ from , to ).

代码示例

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

3.System.arraycopy

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

我们打开 System.arraycopy 方法的具体实现,发现没有和上面几种拷贝方法的实现过程,System.arraycopy 在前面的 native 可知,这是一个本地方法。

本地方法

1.运行在本地方法栈上

2.底层是由C/C++代码实现的

System.arraycopy 没有返回值,第一个参数原数组(要拷贝的数组),第二个参数是原始数组要拷贝的下标,第三个参数是目的地数组 ,第四个参数是 目的地数组的下标,第五个数组是要拷贝的长度.

代码示例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

注意点:

System.arraycopy 最后一个参数 ——要拷贝的数组长度,这个数据不能超过原数组的长度,否则编辑器会发生错误报告:数组越界。

4.数组名.clone —-> 产生当前数组的一个副本

功能: 产生一个当前数组的一个副本。

代码示例:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

3. 找数组中的最大元素

题目内容: 给定一个整型数组, 找到其中的最大元素 (找最小元素同理)

代码实现:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

4.求数组中元素的平均值

题目内容

给定一个整型数组, 求平均值

代码实现:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

注意点:

最后求 aver 方法中平均值 average 时 sum要记得 sum * 1.0,这样算出的平均值才是 double 类型的数据。

5.查找数组中指定元素(顺序查找)

题目内容

给定一个数组, 再给定一个元素, 找出该元素在数组中的位置.

代码实现

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

6.查找数组中指定元素(二分查找)
针对有序数组, 可以使用更高效的 二分查找 .

什么叫有序数组?

有序分为 “升序” 和 “降序” 如 1 2 3 4 , 依次递增即为升序. 如 4 3 2 1 , 依次递减即为降序.

以升序数组为例, 二分查找的思路是先取中间位置的元素, 看要找的值比中间元素大还是小. 如果小, 就去左边找; 否则就去右边找.

代码实现:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

二分查找的具体思路可以到我的往期博客—— 有序数组中查找具体数字n(二分查找) 了解详情。

7.检查数组的有序性

题目内容

给定一个整型数组, 判断是否该数组是有序的(升序)

代码实现:

爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

注意点:

要记得检查传入数组是否为 null ,如果传入的 arr 数组为 null ,此时返回 false 类型。

8.数组排序(冒泡排序)
题目内容

给定一个数组, 让数组升序 (降序) 排序.

算法思路

每次尝试找到当前待排序区间中最小(或最大)的元素, 放到数组最前面(或最后面).

代码实现:

冒泡排序 的具体详解可以到我的往期博客—— 排序算法之冒泡排序 查看,这里就不过多介绍。

9.数组逆序

题目内容

给定一个数组, 将里面的元素逆序排列.

思路

设定两个下标, 分别指向第一个元素和最后一个元素. 交换两个位置的元素.

然后让前一个下标自增, 后一个下标自减, 循环继续即可

代码实现:

五、 二维数组

二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组.

规则的二维数组

(1)二维数组的定义

(2)内存中的二维数组

以上面的 int [ 2 ][ 3 ]为例

我们之前说过二维数组本质上是一个特殊的一维数组。

这个数组的每一行 arr [0] 、arr [1] ,构成了一个一维数组,每一行存放着指向每一列数据的地址。

每一列也是一个单独的一维数组,指向堆中的每一个数据。

(3) 二维数组的打印

知道了二维数组在内存中的存放与指向,所以我们知道 arr.length 得出的就是 行的个数 , arr [ i ].length 得出的就是 列的个数。

  1. for 循环打印

我们对 这个二维数据进行 for 循环 打印。

代码示例:

打印结果:

2.for-each 打印

如果我们用 for-each 打印,代码示例:

打印结果如下:

3.Arrays 工具类 打印

在一维数组中,我们想要将数组转化为字符串打印用的是 Arrays.toString ( ) 。那么二维数组转化为字符串的工具类是什么呢?

如果我们用 Arrays.toString ( ) 进行打印

结果打印的是 arr 行代表的数组内容——列代表的一维数组的地址。显而易见 Arrays.toString ( ) 无法打印出二维数组的全部内容。

我们查找 JDK 文档发现了 deepToString( ) 工具类。

功能:返回指定数组的 “ 深度内容 ” 的字符串表示形式。

我们用 deepToString()进行打印…

结果如下:

成功打印出二维数组的内容。

deepToString ( ) 可以正确的打印出二维数组的全部数据。

不规则的二维数组

在C语言中,我们定义二维数组可以 只定义列,不用规定行的值。

C语言中数组的定义

而在Java中我们只能 定义行,列不用规定值。

Java中不规则二维数组的定义

什么是不规则的二维数组?

在之前的规则的二维数组中,每一行的数据个数都相同,列数也相同。而不规则的二维数组,规定了行数,列数由我们自己定,每一行有多少列由我们自己规定。

(1)不规则二维数组的定义

编译结果:

首先我们规定了一个 有两行的二维数组

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

我们自己给每一行的数组规定有多少列。

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

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

这就是不规则的二维数组的定义。

(2)内存中的二维数组

与规则的二维数组内存存储基本相同。

(3)方式

同理, 还存在 “三维数组”, “四维数组” 等更复杂的数组, 只不过出现的频率都很低。

今日份分享已结束,请大家多多包涵和指点!

文章来源:智云一二三科技

文章标题:爆肝!清华教授耗时三天三夜总结完整版Java数组笔记,网友:膜拜

文章地址:https://www.zhihuclub.com/195120.shtml

关于作者: 智云科技

热门文章

网站地图