数组即同类型数据的有序集合。数组在 JAVA 中是引用数据类型,引用数据类型值都存储在堆中。数组定义后长度不可变。
声明一个数组就是在堆内存中开辟一块连续地址的内存空间,变量名指向的就是数组连续空间的首地址,通过首地址可以遍历数组所有元素。初始化一个整形数组:
int[] arr = new int[]{1, 2, 3, 4, 5};
内存存储:
一、创建数组
Java 中创建数组有多种方式:
type[] arrayName; // 推荐使用方式type arrayName[];
如下:
int[] arr1; // 声明一个整型数组String arr2[]; // 声明一个字符串数组
因为数组是引用数据类型,堆中并未创建数组对象值,所以这里声明的数组只是在栈中声明了一个变量,没有指向数组实际值,不能参与初始化以外的操作。
数组声明并初始化方式:
type[] arrayName = new type[num]; // num 数组存储数据个数type[] arrayName = new type[]{v1, v2, v3}; // 声明并赋值type[] arrayName = {v1, v2, ...}; // 简写方式,直接初始化对应值,数组大小就是初始值个数
编译器会给未初始化数组的所有元素设置默认值。整型数组默认值为 0,布尔型数组默认值为 false,字符型数组默认值为空字符 '',对象数组默认值为 null,字符串属于对象默认也是 null。
注意因为数组的长度不可变,当进行超出数组长度限制的操作时会报错:ArrayIndexOutOfBoundsException。声明并初始化数组:
int[] arr1 = new int[10]; // 初始化一个长度为 10 的数组String[] arr2 = new String[2]; // 初始化一个长度为 2 的字符串数组char[] arr3 = new char[]{'a', 'b', 'c'}; // 初始化并赋值一个长度为 3 的数组char[] arr4 = {'a', 'b', 'c'}; // 简写方式,数组的大小就是初始值的个数
因为数组是引用数据类型,传参时实际传的是数组的引用,对数组的操作都会映射到实际值上。如下:
二、多维数组
本质上并没有所谓的多维数组,只不过是一维数组的每个元素值也是数组类型,所以看起来就像多维数组。这种嵌套可以一直下去到 n 维数组,逻辑上维度没有限制,但 JVM 规范将维度的数量限制在 255,超出报错。声明并初始化多维数组:
int[][] arr1 = new int[2][3]; // 初始化一个 2 维整型数组,默认值为 0String[][][] arr2 = new String[2][3][2]; // 初始化一个 3 维字符串数组,默认值为 nullint[][] arr3 = {{1, 2}, {3, 4}, {5, 6}}; // 初始化并赋值一个 2 维整型数组 System.out.println(Arrays.deepToString(arr1));System.out.println(Arrays.deepToString(arr2));System.out.println(Arrays.deepToString(arr3));
打印值:
三、数组常用操作
1.数组遍历
public static void main(String[] args) {int[] arr = new int[3];for (int i = 0; i < arr.length; i++) {arr[i] = i + 1;}System.out.println(Arrays.toString(arr)); // 输出 [1, 2, 3]}
如果不需要使用数组小标的化可以使用简化语法:for each,格式为:
for (type item : arrName) {... // 操作}
如:
public static void main(String[] args) {String[] arr = new String[]{"hello", "world", "!!"};for (String v : arr) {System.out.println(v); // 循环输出 arr 中的字符串}}
2.数组复制
有四种复制方式,效率由高到低:
1. System.arraycopy2. clone3. Arrays.copyOf4. for 循环
1) System.arraycopy() 系统提供的方法:
/*** @param src 原数组* @param srcPos 拷贝原数组起始位置* @param dest 目标数组* @param destPos 目标数组起始位置* @param length 拷贝数组元素个数*/public static void native arraycopy(Object src, int srcPos, Object dest, int destPos, int length);
示例:
2) clone 对象克隆:
int[] src = {1, 2, 3};int[] dest = src.clone();
3) Arrays.copyOf、Arrays.copyOfRange 方法
int[] src = {1, 2, 3};int[] dest1 = Arrays.copyOf(src, 3);int[] dest2 = Arrays.copyOfRange(src, 1, 3);System.out.println(Arrays.toString(dest1)); // 输出:[1, 2, 3]System.out.println(Arrays.toString(dest2)); // 输出:[2, 3]
4) for 循环,挨个元素复制
int[] src = new int[]{1, 2, 3};int[] dest = new int[3];for (int i = 0; i < src.length; i++) {dest[i] = src[i];}System.out.println(Arrays.toString(dest)); // 输出:[1, 2, 3]
3.数组转字符串
Arrays.toString、Arrays.deepToString 方法
int[] arr1 = {1, 2, 3};String[][] arr2 = {{"aa", "BB"}, {"cc", "CC"}};System.out.println(Arrays.toString(arr1)); // 输出:[1, 2, 3]System.out.println(Arrays.deepToString(arr2)); // 输出:[[aa, BB], [cc, CC]]
4.数组排序
Arrays.sort 方法
static void sort(int[] a) // 对整型数组比较后按升序排序static void sort(int[] a, int fromIndex, int toIndex) // 对整型数组比较指定范围数据按升序排序public static void sort(T[] a,Comparator c) // 根据指定比较器产生的顺序对指定对象数组进行排序public static void sort(T[] a,int fromIndex,int toIndex,Comparator c) // 根据指定比较器产生的顺序对指定对象数组的指定范围进行排序
如:
int[] arr1 = {3, 2, 1};int[] arr2 = {5, 4, 3, 2, 1};Arrays.sort(arr1);Arrays.sort(arr2, 1, 4);System.out.println(Arrays.toString(arr1)); // 输出:[1, 2, 3]System.out.println(Arrays.toString(arr2)); // 输出:[5, 2, 3, 4, 1]
5.数组查找/搜索
Arrays.binarySearch 方法
Arrays.binarySearch(Object[] arr, Object key)arr:要搜索的数组,搜索前必须对数组先进行 sort 排序key:要搜索的值返回值:如果 key 在 arr 中,则返回搜索值得索引,否则返回 -1 或 -[插入点索引值]插入点索引值:1) key 不在 arr 中,且在数组值范围内,从 1 开始计数,索引值为 -[插入点索引值];2) key 不在 arr 中,且大于数组内元素,索引值为 -[arr.length + 1];3) key 不在 arr 中,且小于数组内元素,索引值为 -1。Arrays.binarySearch(Object[] arr, int fromIndex, int toIndex, Object key)arr:要搜索的数组,搜索前必须对数组先进行 sort 排序fromIndex:查找起始位置(包含)toIndex:查找结束位置(不包含)key:要搜索的值返回值:如果 key 在 arr 查找范围中,则返回搜索值得索引,否则返回 -1 或 -[插入点索引值]插入点索引值:1) key 不在 arr 中,且在数组值范围内,从 1 开始计数,索引值为 -[插入点索引值];2) key 不在 arr 中,且大于范围数组内元素,索引值为 -[toIndex + 1];3) key 不在 arr 中,且小于范围数组内元素,索引值为 -[fromIndex + 1]。
如:
int[] arr = {8, 7, 3, 2, 1};Arrays.sort(arr); // 查找之前必须对数组排序int a = Arrays.binarySearch(arr, 3);int b = Arrays.binarySearch(arr, 5);int c = Arrays.binarySearch(arr, 1, 4, 7);int d = Arrays.binarySearch(arr, 1, 4, 8);System.out.println(a); // 输出:2System.out.println(b); // 输出:-4System.out.println(c); // 输出:3System.out.println(d); // 输出:-5
6.数组比较
Arrays.equals、Arrays.deepEquals 方法,比较的数组必须是相同类型。
String[] arr1 = {"hello", "world"};String[] arr2 = {"hello", "world", "!"};boolean re = Arrays.equals(arr1, arr2);System.out.println(re); // 输出:false
7.数组填充
Array.fill 方法
String[] arr = new String[3];Arrays.fill(arr, "a");System.out.println(Arrays.toString(arr)); // 输出:[a, a, a]
8.数组转集合 ArrayList
Arrays.asList 方法
import java.util.Arrays;import java.util.List;public class Test {public static void main(String[] args) {String[] arr = {"aa", "bb", "cc"};List list = Arrays.asList(arr);System.out.println(list.get(1)); // 输出:bbSystem.out.println(Arrays.deepToString(list.toArray())); // 输出:[aa, bb, cc]}}
ArrayList 集成封装了对应的增删改查等操作方法,具体查看 List 接口。
四、可变数组
Java 中数组定义后长度不可变。要实现可变数组,可以通过赋值新数组,或通过上面说的 ArrayList,来实现。
赋值新数组:
import java.util.Arrays;public class Test {public static void main(String[] args) {String[] arr1 = {"aa", "bb"};String[] arr2 = {"cc"};String[] newArr = new String[3];System.arraycopy(arr1, 0, newArr, 0, arr1.length);System.arraycopy(arr2, 0, newArr, 2, arr2.length);System.out.println(Arrays.toString(newArr)); // 输出:[aa, bb, cc]}}
其他实现方式超出本章范围暂不讨论。