Java数组
文章目录
- 数组的概念
- 数组的特点
- 数组的分类
- 使用一维数组
- 静态初始化
- 动态初始化
- 一维数组的遍历
- 数组元素的默认值
- 一维数组内存分析
- 一维数组在内存中的存储
- 使用二维数组
- 二维数组的遍历
- 二维数组的默认初始化值
- 二维数组的内存分析
- 数组的一些操作
- 扩容与缩容
- 二分查找
- 排序算法概述
- 冒泡排序
- Arrays 工具类的使用
- 数组中的常见异常
数组的概念
数组(Array): 是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通 过编号的方式对这些数据进行统一管理。
数组的特点
- 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类 型和引用数据类型。
- 创建数组对象会在内存中开辟一整块连续的空间。占据的空间的大小,取决于数组的 长度和数组中元素的类型。
- 数组中的元素在内存中是依次紧密排列的,有序的。
- 数组,一旦初始化完成,其长度就是确定的。数组的长度一旦确定,就不能修改。
- 我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
- 数组名中引用的是这块连续空间的首地址。
数组的分类
1、按照元素类型分:
- 基本数据类型元素的数组:每个元素位置存储基本数据类型的值
- 引用数据类型元素的数组:每个元素位置存储对象(本质是存储对象的首地址)
2、按照维度分:
- 一维数组:存储一组数据
- 二维数组:存储多组数据,相当于二维表,一行代表一组数据,只是这里的二维表每 一行长度不要求一样。
使用一维数组
1.数组的声明
//推荐
元素的数据类型
[] 一维数组的名称
;
//不推荐
元素的数据类型
一维数组名
[];
静态初始化
数组变量的初始化和数组元素的赋值操作同时进行,那就称为静态初始化。本质是用静态数据(编译时已知)为数组初始化。此时数组的长度由静 态数据的个数决定。
- 方式一: 数据类型[] 数组名 = new 数据类型[]{元素 1,元素 2,元素 3,…};
- 方式二: 数据类型[] 数组名;
数组名 = new 数据类型[]{元素 1,元素 2,元素 3,…};
动态初始化
数组变量的初始化和数组元素的赋值操作分开进行,即为动态初始化。动态初始化中,只确定了元素的个数(即数组的长度),而元素值此时只是默认值,还并未真正赋自己期望的值。真正期望的数据需要后续单独一个一个赋值。
- 数组存储的元素的数据类型[] 数组名字 = new 数组存储的元素的数据类型[长度];
或 - 数组存储的数据类型[] 数组名字;
数组名字 = new 数组存储的数据类型[长度];
public static void main(String[] args) {
//数组声明
double[] prices;
//数组初始化
prices = new double[]{20.32,23.2};
//静态初始化
int[] arr = new int[]{1,2,3,4,5};//正确
String[] foods;
foods = new String[]{"韭菜"};
//动态初始化
String[] foods2 = new String[4];
int[] foods3 = new int[5];
int[] foods3;
foods3 = new int[5];
//其它方式
int arr[] = new int[4];
int[] arr1 = {1,2,3,4};
int[] arr2 = {4};
}
一维数组的遍历
int[] arr = {1,2,3,4};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
数组元素的默认值
对于基本数据类型而言,默认初始化值各有不同。
数组元素类型 | 元素默认初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0.0L |
float | 0.0F |
double | 0.0 |
char | 0或‘\u0000’ |
boolean | false |
引用类型 | null |
一维数组内存分析
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
将内存区域划分为5个部分:程序计数器
、虚拟机栈
、本地方法栈
、堆
、方法区
区域名称 | 作用 |
---|---|
程序计数器 | 程序计数器是 CPU 中的寄存器,它包含每一个线程下一条要执行的指令的地址 |
虚拟 机栈 | 用于存储正在执行的每个 Java 方法的局部变量表等。局部变量表存 放了编译期可知长度 的各种基本数据类型、对象引用,方法执 行完,自动释放。 |
堆内存 | 存储对象(包括数组对象),new 来创建的,都存储在堆内存。 |
方法区 | 存储已被虚拟机加载的类信息、常量、(静态变量)、即时编译器编译后的代码等数据。 |
本地方法栈 | 当程序中调用了 native 的本地方法时,本地方法执行期间的内存区域 |
一维数组在内存中的存储
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr);//[I@36baf30c
}
- 执行main方法
- 堆内存创建内存空间存储数组
- 数组会有自己的内存地址(16进制表示)
- 数组默认值0、0、0
- JVM将数组的内存首地址赋值给引用类型变量arr
赋值操作
public static void main(String[] args) { // 定义数组,存储 3 个元素
int[] arr = new int[3]; //数组索引进行赋值
arr[0] = 1;
arr[1] = 2;
arr[2] = 3;
int[] arr2 = arr;
arr2[1] = 4;
}
使用二维数组
二维数组声明的语法格式:
//推荐
元素的数据类型
[][] 二维数组的名称
;
//不推荐
元素的数据类型
二维数组名
[][];
//不推荐
元素的数据类型
[] 二维数组名
[];
public static void main(String[] args) {
//静态初始化
int[][] arr = new int[][]{{1,2,3},{4,5},{6,7,8,9}};
int[][] arr;
arr = new int[][]{{1,2,3},{4,5,6},{7,8,9,10}};
//动态初始化
String[][] arr6 = new String[3][4];
double[][] arr7 = new double[2][];
//其它写法
int arr8[][] = new int[][]{{1,2,3},{4,5,6}};
int[] arr9[] = new int[][]{{1,2,3},{4,5,6}};
int arr10[][] = {{1,2,3},{4,5,6}}; //类型推断
String arr11[][] = new String[3][4];
}
二维数组的遍历
int arr[][] = new int[][]{{1,2,3},{4,5,6}};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
二维数组的默认初始化值
- 外层元素默认存储地址值
- 内层元素按一维数组元素类型
public static void main(String[] args) {
//第一种情况
int[][] arr1 = new int[3][2];
//外层元素
System.out.println(arr1[0]);//[I@36baf30c
System.out.println(arr1[1]);//[I@7a81197d
//内层元素
System.out.println(arr1[0][0]);//0
String[][] arr2 = new String[3][2];
//外层元素
System.out.println(arr2[0]); //[Ljava.lang.String;@5ca881b5
//内层元素
System.out.println(arr2[0][1]); //null
//第二种情况
int[][] arr3 = new int[4][];
//外层元素
System.out.println(arr3[0]); //null
//内层元素
System.out.println(arr3[0][0]); //报错-空指针异常
}
二维数组的内存分析
举例1:
public static void main(String[] args) {
String[][] arr1 = new String[3][2];
int[][] arr2 = new int[4][];
arr2[1] = new int[5];
arr2[1][1] = 1;
arr2[2][2] = 1; //报错
}
举例2:
public static void main(String[] args) {
int[][] arr1 = new int[3][]'
arr1[0] = new int[3];
arr1[1] = new int[]{1,2,3};
arr1[0][1] = 1;
arr1 = new int[2][];
}
数组的一些操作
扩容与缩容
int[] arr = new int[]{1,2,3,4,5};
//扩容一倍
int[] newArr = new int[arr.length << 1];
//缩容 删除索引为 4 的元素
int[] arr = {1, 2, 3, 4, 5, 6, 7};
int delIndex = 4;
for (int i = delIndex; i < arr.length - 1; i++) {
arr[i] = arr[i + 1]; }
arr[arr.length - 1] = 0;
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]); //1、2、3、4、6、7、0
}
}
二分查找
int[] arr30 = new int[]{-99, -54, -2, 0, 2, 20};
boolean flag = false;
int value = -541;
int head = 0;
int end = arr30.length - 1;
for (int i = 0; i < arr30.length; i++) {
int middle = (head + end) / 2;
if (arr30[i] == value) {
System.out.println("找到了" + arr30[i] + "索引是" + i);
flag = true;
break;
} else if (arr30[middle] > value) {
end = middle - 1;
} else {
head = middle + 1;
}
}
if (!flag) {
System.out.println("没找到");
}
排序算法概述
排序算法分类:内部排序和外部排序
- 内部排序:整个排序过程不需要借助于外部存储器(如磁盘等),所有排序 操作都在内存中完成。
- 外部排序:参与排序的数据非常多,数据量非常大,计算机无法把整个排 序过程放在内存中完成,必须借助于外部存储器(如磁盘)。外部排序最常 见的是多路归并排序。可以认为外部排序是由多次内部排序组成。
常见时间复杂度所消耗的时间从小到大排序:
O(1) < O(logn) < O(n) < O(nlogn) < O(n^2) < O(n^3) < O(2^n) < O(n!) < O(n^n)
冒泡排序
int[] arr = {1, 3, 2, 1, -1, -1};
for (int i = 1; i <= arr.length - 1; i++) {
for (int j = 0; j < arr.length - i; j++) {
if (arr[j] > arr[j + 1]) {
int temp = arr[j];
arr[j] = arr[j + 1];
arr[j + 1] = temp;
}
}
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
Arrays 工具类的使用
java.util.Arrays 类即为操作数组的工具类,包含了用来操作数组(比如排序和搜索)的各种方法
- 数组比较是否相等: Arrays.equals(arr1,arr2);
- 输出数组元素信息 Arrays.toString(arr);
- 将指定值填充到数组中: Arrays.fill(arr,10);
- 使用快排: Arrays.sort(arr);
- 二分查找元素: Arrays.binarySearch(arr,3);
数组中的常见异常
- 数组角标越界异常(索引超出)
- 空指针异常(为null时访问元素或方法报错
NullPointerException
)