Java - 数组
一、数组的概念
数组概念: 数组是用于存储数据的长度固定的容器,保证多个数据的数据类型要一致
数组的特点
- 数组的长度一旦确定就不能修改
- 创建数组时会在内存中开辟一整块连续的空间
- 存取元素的速度快,因为可以通过
[下标]
,直接定位到任意一个元素
数组的分类
- 按照维度分:
- 一维数组:存储一组数据
- 二维数组:一行代表一组数据,每一行长度可以不一样
- 按照元素类型分:
- 基本数据类型的元素:存储数据值
- 引用数据类型的元素:存储对象(本质上存储对象的首地址)
无论数组的元素是基本数据类型还是引用数据类型,数组本身都是引用数据类型
二、一维数组的声明与使用
1、一维数组的声明
一维数组的声明格式
数组类型[] 数组的名称;
(推荐)数组类型 数组名[];
声明数组三要素
- 数组的维度:
[]
表示一维,[][]
表示二维 - 数组的元素类型:可以是任意的Java的数据类型
- 数组名:引用数据类型的变量,因为它代表一组数据
- 数组的维度:
2、一维数组的动态初始化
动态初始化:确定元素的个数(即数组的长度),而元素此时只是默认值,并不是真正的数据
动态初始化格式
元素的数据类型[] 数组名 = new 元素的数据类型[长度];
元素的数据类型[] 数组名;``数组名 = new 元素的数据类型[长度];
new
:创建数组使用的关键字。因为数组本身是引用数据类型,所以要用new创建数组对象
- 数组元素的默认值
数组元素类型 | 元素默认初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
char | 0 |
boolean | false |
引用类型 | null |
3、一维数组的静态初始化
静态初始化:用静态数据为数组初始化,此时数组的长度由静态数据的个数决定
静态初始化格式
数据类型[] 数组名 = {元素1,元素2,元素3...};
(不能分两个语句写)数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
数据类型[] 数组名;``数组名 = new 数据类型[]{元素1,元素2,元素3...};
4、一维数组的使用
获取数组长度(元素总个数):
数组名.length
访问数组元素:
数组名[下标]
数组的下标范围:
[0, 数组名.length-1]
5、一维数组的遍历
- 数组遍历: 将数组中的每个元素分别获取出来
1 | for(int i=0; i<arr.length; i++){ |
三、一维数组内存分析
1、Java虚拟机的内存划分
为了提高运算效率,空间进行了不同区域的划分,每一片区域都有特定的处理数据方式和内存管理方式
区域名称 | 作用 |
---|---|
程序计数器 | 程序计数器是CPU中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
本地方法栈 | 当程序中调用了native的本地方法时,本地方法执行期间的内存区域 |
方法区 | 存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据 |
堆内存 | 存储对象(包括数组对象),new来创建的,都存储在堆内存 |
虚拟机栈 | 用于存储正在执行的每个Java方法的局部变量表等。局部变量表存放了编译期可知长度的各种基本数据类型、对象引用,方法执行完,自动释放 |
2、一维数组在内存中的存储
因为第一个元素距离数组首地址间隔0个单元格,所以数组下标从0开始
创建一个数组(方法栈),则会创建了一个连续的内存空间(堆),数组变量指向的是对象的首地址
- 将一个数组变量赋值到另一个数组变量,两个数组变量本质上代表同一个数组
直接打印数组名出现的不是数组的首地址,因为数组是引用数据类型,打印数组名时,会自动调用数组对象的toString()方法,该方法默认实现的是
对象类型名@该对象的hashCode()值的十六进制值
,这个值不一定就是对象的内存地址,和不同品牌的JVM产品的具体实现有关
例如:Oracle的OpenJDK中给出了5种实现,其中有一种是直接返回对象的内存地址,但是OpenJDK默认没有选择这种方式
四、数组的常见算法
1、数组统计
1 | public class Test08ArrayElementSum { |
2、数组找最值
1 | public class Test11ArrayMax { |
3、数组的元素查找
1 | public class Test14ArrayOrderSearch { |
4、数组的元素翻转
1 | public class Test17ArrayReverse { |
5、数组元素排序
冒泡排序原理:比较两个相邻的元素,将值大的元素交换至右端
1 | /* |
6、算法时空复杂度
- 时间复杂度:一个算法中的语句执行次数称为语句频度或时间频度,记为T(n)。n称为问题的规模,一般情况下,算法中基本操作重复执行的次数是问题规模n的某个函数,用T(n)表示,当n不断变化时,时间频度T(n)也会不断变化。若有某个辅助函数f(n),使得当n趋近于无穷大时,T(n)/f(n)的极限值为不等于零的常数,则称f(n)是T(n)的同数量级函数。记作T(n)=O(f(n)),称O(f(n)) 为算法的渐进时间复杂度,简称时间复杂度。
常见的算法时间复杂度由小到大依次为:Ο(1)<Ο(log2n)<Ο(n)<Ο(nlog2n)<Ο(n2)<Ο(n3)<…<Ο(2n)<Ο(n!)
- 空间复杂度(Space Complexity):类似于时间复杂度的讨论,一个算法的空间复杂度S(n)定义为该算法所耗费的存储空间,它也是问题规模n的函数
- 稳定性:排序算法一定会设计到数组元素位置的交换。如果两个元素相等,无论它们原来是否相邻,在排序过程中,最后它们变的相邻,但是它们前后顺序并没有改变,就称为稳定的,否则就是不稳定的
五、二维数组的声明与使用
1、二维数组的声明
二维数组:本质上就是元素为一维数组的数组
二维数组的标记:
[][]
二维数组声明的语法格式
元素的数据类型[][] 二维数组名;
(推荐)元素的数据类型 二维数组名[][];
元素的数据类型[] 二维数组名[];
int[] x, y[];
,此处x是一维数组,y是二维数组
2、二维数组动态初始化
动态初始化格式
- (1)规则二维表:每一行的列数是相同的
元素的数据类型[][] 二维数组名 = new 元素的数据类型[m][n];
- (2)不规则二维表:每一行的列数不一样
元素的数据类型[][] 二维数组名 = new 元素的数据类型[总行数][];
二维数组名[行下标] = new 元素的数据类型[该行的总列数];
3、二维数组的静态初始化
静态初始化格式
元素的数据类型[][] 二维数组的名称 = {{第一行的值列表}, ...{第n行的值列表}};
(不能分两个语句写)元素的数据类型[][] 二维数组名 = new 元素的数据类型[][] {{第一行的值列表}, ...{第n行的值列表}};
元素的数据类型[][] 二维数组名;``二维数组名 = new 元素的数据类型[][]{{第一行的值列表}, ...{第n行的值列表}};
new 数据类型[][]
中不能写数字,因为行数和列数,由{}
的元素个数决定
4、二维数组的使用
- 获取二维数组长度(行数):
二维数组名.length
- 访问二维数组某一行:
二维数组名[行下标]
- 访问某一行的列数:
二维数组名[行下标].length
- 访问某一个元素:
二维数组名[行下标][列下标]
- 获取行下标的范围:
[0, 二维数组名.length-1]
5、二维数组的遍历
1 | for(int i=0; i<二维数组名.length; i++){ //二维数组对象.length |