更好的阅读体验:点这里 ( )
5 数组
前面我们保存数据的时候,是将数据保存在变量中,如果要保存2个数据,就声明2个变量。
如果要保存100个数据呢,1000个数据…呢?
所以就需要保存数据的集合来保存批量的数据,下面介绍一下数组。
数组的主要特点:
- 有序,顺序排列;
- 只能存储相同类型的元素;
- 大小在创建的时候就确定了,大小不可变;
5.1 一维数组
1 初始化
同样,数组和变量一样,在使用之前也要进行声明和初始化,数组变量是引用类型的。
定义数组就是类型加上 , 可以在类型后,也可以在变量名后,Java 中推荐放在类型后面。
中, 表示是数组, 表示是整形的数组,里面只能放 类型的数据。
2 基础操作
获取长度
使用 属性可以获取到数组的长度。
访问元素
访问数组元素是使用下标来访问的,从0开始。
注意不要越界,下标越界会报错。
因为数组的长度创建后就无法更改了,所以我们无法删除和添加更多到元素到数组中,只能访问和修改数组中的元素。
例如现在创建了一个长度为20的数组,添加学生姓名,现在发现长度不够了,像扩大数组的长度,放更多的元素,这种做法你只能想想。实际上你只能重新创建一个更大的数组,将这个数组的数据复制到更大的数组中。
访问元素的时候一定要注意,不要超越数组的长度,例如:
长度为 5 的数组,最后一个元素的下标 index 为 4,所以不能大于4,否则会越界报错。
3 遍历数组
遍历就是依次访问数组中的元素。
使用 循环遍历
注意编辑结束的条件是: ,是用 for 循环,可以对数据进行遍历赋值和访问。
使用 循环遍历
循环也叫 ,使用起来更加简洁,但是不能使用 循环进行赋值。
循环,冒号前面是依次取出的数组中的每个元素。
4 数组元素的默认值
动态初始化方式定义的数组,例如 ,没有设置数组中元素的值,元素是有默认值的。对于基本数据类型,byte、short、int、long、char 类型的数组,默认值为 ,float、double 类型的数组,默认值为 ,boolean 类型数组,默认值为 。对于引用类型的数组,元素的默认值都是 。
举个栗子:
方法可以以字符串的形式打印数组中的内容。
5 内存结构
数组是引用类型的,和普通的数据类型有一些不同。
对于上面的代码,在内存中的结构是这样的:
内存中会有不同的存储数据的区域,这里使用的有栈和堆,栈中存放的是局部变量,也就是方法中定义的变量,现在我们定义的变量都是在方法中的,也就是 main 方法,所以 numbers 变量是存储在栈中的,但是右边的数组值是存储在堆中的,numbers 变量中存储的是一个地址值,是数组的首地址(第一个元素的起始地址,也就是1的起始地址,上面的地址值是胡诌的)。
再看一段代码:
上面的代码,重新将一个数组赋值给 numbers,内存结构如下:
java基础 数组
numbers 被赋值为一个新的数组,那么存储的是新的数组的首地址值,numbers 与新的数组建立关系,与原来的数组断开联系了。
5.2 二维数组
一维数组看上去只是一行或一列数据:
二维数组可以存储类似一个表格的数据:
二维数组其实是:一维数组的每一个元素也是一个数组。
也就是一个一维数组中的每个元素,存储的都是一维数组的地址,地址指向的都是第二层一维数组,如下图:
1 初始化
现在看一下上面定义二维数组的内存结构:
内存结构如下:
首先在栈中定义了一个变量 numbers1,numbers1 存储的是第一层数组的首地址,第一层中的各个元素存储的是第二层各个数组的首地址。
内存结构如下:
内存结构如下:
内存结构如下:
在上面第一层数组的值是空的,还没有指向第二层数组,后面可以创建第二层数组,将地址赋值给第一层数组。
2 基础操作
获取长度
也是使用 属性可以获取到数组的长度。
但是数组中第二层数组元素的长度需要获取到第一层数组元素再获取长度。
访问元素
访问二维数组中的元素,需要通过两个 获取,第一个表示获取到的是第一层的元素,第二个才是获取到二维数组中的元素。
不是数组的长度无法更改吗,为什么可以这样操作 ,这是将第一层数组指向了一个新的第二层数组而已。
3 遍历数组
使用 循环遍历
遍历二维数组,需要两层 for 循环。
上面使用 for 循环对二维数组进行了遍历赋值和打印。
注意:第一层 for 循环取的是第一层数组的长度,第二层数组取的是第二层数组的长度。
执行结果:
二维数组的内容:
0 1 2
10 11 12
20 21 22
使用 循环遍历
使用 循环看上去要简洁很多,第一层 循环获取到的每个元素其实是一维数组,然后第二层 循环遍历每个一维数组。
5.3 数组的其他操作
1 数组复制
将一个数组的值赋值给另一个数组,该如何操作。
先看下面的代码,看看能否将 的值复制给 :
很明显上面并不能将 的值复制给 ,因为后来修改 的值, 的值也发生了变化,说明不是独立的两份数据。
其实内存结果是下面这样的:
初始化两个数组的时候, 和 还是独立的数据,后来 则将 number1 中存储的地址值赋给了 ,那么 也之下那个了 指向的堆中的内存地址。
所以我们在复制数组的时候,需要遍历数组,一个一个元素的去复制:
Java API 给我们提供了很多可以用的类,可以帮我们完成很多功能,不用需要我们编写代码去实现。
所谓的 Java API 就是为 Java 编程语言提供的可以直接使用的类库和方法。
例如上面的数组复制功能,也可以调用 Java 提供的 API :
参数说明:
- 第一个参数:源数组,数据从哪里来;
- 第二个参数:从源数组的哪个位置开始复制;
- 第三个参数:目标数组,数据复制给谁;
- 第四个参数:放到目标数组哪个位置;
- 第五个参数:要复制的数据的长度;
还有另外的API : 和 ,也可以完成数组的复制,不过是重新开辟了内存空间。
在上面的代码中,并没有修改原来 的内存空间的数据,而是重新开辟了内存控制,然后将内存地址给了变量 。
的第一个参数是源数组,第二个是复制的数据长度,复制是从索引0开始复制的。
的第一个参数是源数组,第二个参数是复制的起始位置(包含该位置),第三个参数是复制的结束位置(不包含该位置)。
2 冒泡排序
思考:
一个 类型的数组,其中的元素大小没有顺序,该如何实现将其中的元素由大到小排列呢?
原理
冒泡排序是数组排序中一个非常经典的算法。
原理是:依次比较相邻的两个数,将比较小的数放在前面,比较大的数放在后面。
首先取出第一个数,依次和后面的元素比较,如果比后面的元素大,就交换,否则继续用后面的数比较。
用图示例一下:
上面只是第一轮的比较,会找到最大的数,排到数组末尾;第二轮需要拿4进行比较,最终找到第二大的数6,6会沉到7前面,就不用和7比较了,也就是每比较一次,在最后面就会少比较一次,因为大的都沉到底部了,后面都是排序好的,自然就不用比较了。
冒泡算法因为在排序的过程中,较大(或较小)的元素会像气泡一样从数组的一端“浮”到另一端,像冒泡一样。
Java代码实现
下面使用 Java 代码实现冒泡排序。
同样,在实际开发中也不需要我们手写排序算法, Java API 也提供了排序的方法,可以直接调用排序方法来对数组进行排序,只是 Java API 底层不是用冒泡排序实现的,冒泡排序的效率不是很高。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.bianchenghao6.com/h6javajc/3370.html