4 数组
4.1 概念
数组:是相同类型数据的有序集合,相同类型的若干个数据,按照一定先后次序排列组合而成。其中,每一个数据称作一个数组元素,每个数组元素可以通过一个下标来访问它们
4.2 特点
- 数组长度是确定的,数组一旦被创建,它的大小就是不可以改变的(有局限性)
 - 存放的元素类型相同
 - 元素可以是任何数据类型,包括基本类型和引用类型
 - 可以存放重复的元素
 下标:用来表示数组元素的顺序
- 数组下标是从0开始,第一个元素下标为0,可以通过下标访问数组元素
 
4.3 数组的创建和应用
4.3.1 数组的初始化
一维数组
等号左边:
- 元素类型[]  数组名   例如:
int[] arr - 元素类型  数组名[]   例如:
int arr[] 
- 元素类型[]  数组名   例如:
 等号右边:
静态初始化:(根据元素的个数来确定数组的长度)
- new 元素类型[]{元素,元素…}   例如:
new int[]{1, 3, 5},代表有3个int类型元素的数组 - {元素,元素…}   例如:
{1, 3, 5},代表是有3个元素的数组 
- new 元素类型[]{元素,元素…}   例如:
 动态初始化:(根据元素的个数来确定数组的长度)
- new 元素类型[5]   例如:
new String[3],代表是一个可以存放3个String类型元素的数组 
- new 元素类型[5]   例如:
 
示例:
int arr[] = new int[3];int arr[] = new int[]{1, 2, 3};int[] arr = {4, 5, 6};
二维数组
等号左边:
- 元素类型[]  数组名   例如:
int[][] arr - 元素类型  数组名[]   例如:
int arr[][] 
- 元素类型[]  数组名   例如:
 等号右边:
静态初始化:
- new 元素类型[]{元素,元素…}   例如:
new int[]{{1, 2, 3}, {4, 5}, {6}} - {元素,元素…}   例如:
{{1, 2, 3}, {4, 5}, {6}} 
- new 元素类型[]{元素,元素…}   例如:
 动态初始化:
- new 元素类型[5]   例如:
new String[3][2]代表可以存放3个元素,每个元素是可以存放2个String类型数据的数组 
- new 元素类型[5]   例如:
 
示例:
int arr[][] = new int[3][2];int arr[][] = new int[][]{{1, 2, 3}, {4, 5}, {6}};int[][] arr = {{1, 2, 3}, {4, 5}, {6}};
4.3.2 数组的访问及遍历
数组的访问
- 通过下标进行访问  例如:
arr[下标] 
- 通过下标进行访问  例如:
 数组的遍历
for循环遍历 例如:for (int i = 0; i < 数组.length; i++) {}- 可以进行数组遍历,并且可以在过程中对数组进行修改
 - 定义下标方式进行遍历
 
增强
for循环遍历(for each循环) 例如:for (数据类型 变量名 : 数组) {}- 只能进行遍历,不能对数据进行修改
 for each遍历的效率比普通for循环高- 采用声明一个临时的变量来保存元素方式遍历,只能访问元素,不能使用这个变量来改变原来数组中的元素
 
4.3.3 代码示例
/*** 数组基本使用*/public class ArrayBase {public static void main(String[] args) {initArray();visitArray();dynamicInit();traversalArray();traversalArrayUpdate();//String[] args 可以接收命令行参数System.out.println(args); // [Ljava.lang.String;@74a14482for (int i = 0; i < args.length; i++) {System.out.println(args[i]);}}// 数组的定义public static void initArray() {// 动态初始化int arr[] = new int[3];// 静态初始化int arr1[] = new int[]{1, 2, 3};int[] arr2 = {4, 5, 6};}// 通过下标访问数组public static void visitArray() {int[] in = new int[]{23,34,645,234,22,46};// 下 标 : 0 1 2 3 4 5System.out.println(in); // [I@1b6d3586 地址System.out.println(in.toString()); // [I@1b6d3586System.out.println(in[0]); // 23System.out.println(in[1]); // 34// 修改数组中的数据in[0] = 0;System.out.println(in[0]); // 0}// 动态初始化public static void dynamicInit() {// 动态初始化String str[] = new String[3];System.out.println(str); // [Ljava.lang.String;@4554617cSystem.out.println(str.toString()); // [Ljava.lang.String;@4554617c// 动态赋值str[0] = "jason";str[1] = "lyl";System.out.println(str[0]); // jasonSystem.out.println(str[1]); // lylSystem.out.println(str[2]); // null -> String (引用数据类型)类型默认值为 nullint ar[] = new int[3];System.out.println(ar[0]); // 0 int 类型默认值为 0}// 数组的遍历public static void traversalArray() {String[] str = new String[]{"张三","李四","王五","23","564"};/** 第一种方式* for循环遍历 快捷键: fori* i : 下标*/for (int i = 0; i < str.length; i++) {System.out.println(str[i]);}/** 第二种方式* foreach循环遍历 快捷键 iter (iterator迭代)* 把 str 中的数据一个一个给 s,并打印输出*/for (String s : str) {System.out.println(s);}// java.util 数组工具类System.out.println(Arrays.toString(str));}// 遍历中修改数据 测试public static void traversalArrayUpdate() {int[] arr = new int[]{1, 3, 5};// for循环修改数组 测试for (int i = 0; i < arr.length; i++) {arr[i] += 1;System.out.println(arr[i]); // 2 4 6}System.out.println(Arrays.toString(arr)); // 可以修改 [2, 4, 6]// foreach循环修改数组 测试for (int i : arr) {i += 1;System.out.println(i); // 3 5 7}System.out.println(Arrays.toString(arr)); // 修改失败 [2, 4, 6]}}
/*** 数组常见问题*/public class ArrayException {public static void main(String[] args) {/** 常见问题** 数组下标越界异常* 报错:Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 4*/String[] str = new String[]{"张三","李四",null,"王五"};// System.out.println(strr[4]);/** 空指针异常* 报错:java.lang.NullPointerException*/String[] str2 = null;// System.out.println(str2[0]);// int len = str2.length; // NullPointerExceptionint len = str.length; // 数组长度跟具体存储的数据多少有关,不是从0开始System.out.println(len); // 4}}
/*** 二维数组*/public class Array2d {public static void main(String[] args) {initArray2d();visitArray2d();traversalArray2d();}// 二维数组的初始化public static void initArray2d() {// 动态初始化// int arr[][] = new int[3][2];int arr[][] = new int[3][];arr[0] = new int[2];arr[1] = new int[2];arr[2] = new int[2];// 静态初始化int arr1[][] = new int[][]{{1, 2, 3}, {4, 5}, {6}};int[][] arr2 = {{1, 2, 3}, {4, 5}, {6}};}// 二维数组的访问及修改public static void visitArray2d() {int arr[][] = new int[][]{{1, 2, 3}, {4, 5}, {6}};// 一维 下标 0 1 2// 二维 下标 0 1 2 0 1 0System.out.println(arr[0][2]); // 3// 修改数据arr[0][2] = 7;System.out.println(Arrays.toString(arr)); // [[I@1b6d3586, [I@4554617c, [I@74a14482]System.out.println(Arrays.toString(arr[0])); // [1, 2, 7]}// 二维数组的遍历public static void traversalArray2d() {int arr[][] = new int[][]{{1, 2, 3}, {4, 5}, {6}};// 双重for循环for (int i = 0; i < arr.length; i++) {// System.out.println(arr[i]);for (int j = 0; j < arr[i].length; j++) {System.out.println(arr[i][j]);}}}}
/*** 数组练习*/public class ArrayTest {public static void main(String[] args) {int[] arr = new int[]{12,23,33,213,11,31,94};testMaxAndMin(arr);int sum = testSum(arr);testAverage(arr, sum);testReversal(arr);testToString(arr);testEqual(arr);testVarages(110, 119, 120);testVarages(arr);}/*** 测试:求最值* @param arr int[]*/public static void testMaxAndMin(int[] arr) {// 求数组最大值int max = arr[0];for (int i = 1; i < arr.length; i++) {if(max < arr[i]){max = arr[i];}}System.out.println("max:" + max);// 求数组最小值int min = arr[0];for (int i = 1; i < arr.length; i++) {if(max > arr[i]){max = arr[i];}}System.out.println("min:" + min);}/*** 测试:求数组总和* @param arr int[]* @return*/public static int testSum(int[] arr) {int sum = 0;for (int i = 0; i < arr.length; i++) {sum += arr[i];}System.out.println("总和: "+sum);return sum;}/*** 测试:求平均数* @param arr int[]* @param sum 数组总和*/public static void testAverage(int[] arr, int sum) {System.out.println("平均数:"+sum/arr.length);}/*** 测试:数组的反转* @param arr int[]*/public static void testReversal(int[] arr) {System.out.println("原数组:" + Arrays.toString(arr));for (int x = 0, y = arr.length-1; x<y; x++,y--) {int temp = arr[x];arr[x] = arr[y];arr[y] = temp;}System.out.println("反转后:" + Arrays.toString(arr));}/*** 测试:遍历数组元素* @param arr int[]*/public static void testToString(int[] arr) {System.out.print("[");for (int i = 0; i < arr.length; i++) {System.out.print(arr[i]+" ");}System.out.print("]");System.out.println();}/*** 测试:判断是否相等* @param arr int[]*/public static void testEqual(int[] arr) {int[] arr1 = arr;// 判断两个数组是否相等boolean bn = Arrays.equals(arr,arr1);System.out.println("是否相等:"+ bn);}/*** 测试:解析可变长参数列表* @param arr 可变长参数列表*/public static void testVarages(int... arr) {for (int i = 0; i < arr.length; i++) {System.out.println(arr[i]);}}}
/*** 数组的拷贝*/public class ArrayTestCopy {public static void main(String[] args) {int[] arr = new int[]{12,23,33,213,11,31,94};testArrayCopy(arr);testArraysUtilCopy(arr);testSystemArrayCopy(arr);testClone(arr);testArray2dCopy();}/*** 浅拷贝和深拷贝区别* @param arr*/public static void testArrayCopy(int[] arr) {// 浅拷贝 - 复制的是引用(引用原来的对象)int[] arr1 = null;arr1 = arr;// 深拷贝 - 复制的是数据(重新创建了一个对象)int[] arr2 = new int[arr.length];for (int i = 0; i < arr.length; i++) {arr2[i] = arr[i];}System.out.println("原数据 arr:" + arr);System.out.println("浅拷贝 arr1:" + arr1);System.out.println("深拷贝 arr2:" + arr2);// 修改浅拷贝数组,会修改原来数组数据arr1[0] = 100;System.out.println("修改浅拷贝后原数据 会改变 arr: " + Arrays.toString(arr));System.out.println("浅拷贝的数据 arr1: " + Arrays.toString(arr1));// 修改深拷贝数组,不会修改原来数组数据arr2[0] = 200;System.out.println("修改深拷贝后原数据 不会改变 arr: " + Arrays.toString(arr));System.out.println("深拷贝的数据 arr2: " + Arrays.toString(arr2));}/*** Arrays工具类拷贝方法 - 深拷贝* @param arr*/public static void testArraysUtilCopy(int[] arr) {int[] arr3 = Arrays.copyOf(arr,arr.length);System.out.println(arr);System.out.println(arr3);System.out.println(Arrays.toString(arr));System.out.println(Arrays.toString(arr3));}/*** System.arraycopy(src, srcPos, dest, destPos, length);* 复制数组解析: (原数组,从原数组的起始位置,目标数组,目标数组的起始位置,要复制的数组长度)* @param arr*/public static void testSystemArrayCopy(int[] arr) {int[] arr4 = new int[arr.length];System.arraycopy(arr, 0 , arr4, 0, arr.length);// int[] arr4 = new int[arr.length-1];// System.arraycopy(arr, 1 , arr4, 0, arr.length-1);System.out.println("arr4: " + Arrays.toString(arr4));System.out.println(arr4 == arr);System.out.println(Arrays.equals(arr4, arr));}/*** clone()方法拷贝* @param arr*/public static void testClone(int[] arr) {int[] clone = arr.clone();System.out.println(clone == arr); // falseSystem.out.println(clone.equals(arr)); // falseSystem.out.println(Arrays.equals(clone, arr)); // trueSystem.out.println(Arrays.toString(clone));}public static void testArray2dCopy() {int[][] arr = new int[][]{{1,2,3},{4,5},{6}};int[][] newArr = new int[3][];System.arraycopy(arr, 0, newArr, 0, arr.length);// 新旧二维数组的内部对象引用是指向同一个地方,所以如果修改数据,新旧数组会同时受到影响System.out.println(Arrays.toString(arr)); // [[I@1b6d3586, [I@4554617c, [I@74a14482]System.out.println(Arrays.toString(newArr)); // [[I@1b6d3586, [I@4554617c, [I@74a14482]arr[0][0] = 100;System.out.println(Arrays.toString(arr[0]));System.out.println(Arrays.toString(newArr[0]));}}
二维数组拷贝内存结构图分析

/*** 数组常用排序方法练习*/public class ArrayTestSort {public static void main(String[] args) {int[] arr = new int[]{3, 5, 8, 2, 1, 6, 9, 4, 7};testArraysSort(arr);testSelectSort(arr);testSelectSortMoreEfficient(arr);testBubbleSort(arr);new ArraySortTest().testObjectSort();}/*** 使用Arrays工具类方法,按升序排列数组* @param arr*/public static void testArraysSort(int[] arr) {Arrays.sort(arr);System.out.println("ArraysSort:" + Arrays.toString(arr));}/*** 选择排序* @param arr*/public static void testSelectSort(int[] arr) {for (int i = 0; i < arr.length; i++) {for (int j = i+1; j < arr.length; j++) {if (arr[j] < arr[i]) {int temp = arr[i];arr[i] = arr[j];arr[j] = temp;}}}System.out.println("SelectSort: " + Arrays.toString(arr));}/*** 效率更高的方法* @param arr*/public static void testSelectSortMoreEfficient(int[] arr) {// 效率较高的排序,减少交换次数,每次比较完后只进行一次交换for (int i = 0; i < arr.length; i++) {int k = i; // 定义k变量,假设下标为k的值最小for (int j = i+1; j < arr.length; j++) {if (arr[j] < arr[k]) {k = j;}}if (k != i) {int temp = arr[i];arr[i] = arr[k];arr[k] = temp;}}// 在for循环外部定义k和temp,这样不用每次在循环时重新在栈上分配空间,只分配一次int k, temp;for (int i = 0; i < arr.length; i++) {k = i;for (int j = i+1; j < arr.length; j++) {if (arr[j] < arr[k]) {k = j;}}if (k != i) {temp = arr[i];arr[i] = arr[k];arr[k] = temp;}}System.out.println("SelectSortMoreEfficient: " + Arrays.toString(arr));}/*** 冒泡排序* @param arr*/public static void testBubbleSort(int[] arr) {// 第一种思路for (int i = arr.length - 1; i >= 1; i--) {for (int j = 0; j <= i - 1; 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-1; i++){for (int j = 0; j < arr.length-1-i; j++) {if (arr[j] > arr[j+1]){// int temp = arr[j];// arr[j] = arr[j+1];// arr[j+1] = temp;swap(arr, j);}}}System.out.println("BubbleSort从小到大:" + Arrays.toString(arr));// 从大到小排序for (int i=0; i<arr.length-1; i++){for (int j = 0; j < arr.length-1-i; j++) {if (arr[j] < arr[j+1]){ // 修改一下条件即可// int temp = arr[j];// arr[j] = arr[j+1];// arr[j+1] = temp;swap(arr, j);}}}System.out.println("BubbleSort从大到小:" + Arrays.toString(arr));}/*** 对象的排序*/public void testObjectSort() {Person[] people = new Person[5];people[0] = new Person(160, 1000);people[1] = new Person(180, 1000);people[2] = new Person(170, 500);people[3] = new Person(180, 500);people[4] = new Person(170, 1500);for (int i = people.length - 1; i >= 1; i--) {for (int j = 0; j <= i - 1; j++) {if (people[j].compare(people[j+1]) < 0) {Person temp = people[j];people[j] = people[j+1];people[j+1] = temp;}}}System.out.println(Arrays.toString(people));for (int i = 0; i < people.length; i++) {System.out.println(people[i]);}}/*** 交换位置* @param arr* @param j*/private static void swap(int[] arr, int j) {int temp = arr[j];arr[j] = arr[j+1];arr[j+1] = temp;}class Person {private int height;private double money;Person(int height, double money) {this.height = height;this.money = money;}/*** 自定义比较方法* @param person* @return 大于返回正数,小于返回负数,等于返回0*/public int compare(Person person) {return height > person.height ? 1: height < person.height ? -1: money > person.money ? 1: money < person.money ? -1: 0;}@Overridepublic String toString() {return "Person{" +"height=" + height +", money=" + money +'}';}}}
/*** 数组练习:数三减一*/public class ArrayTestCount3Quit {public static void main(String[] args) {testCount3Quit();testCount3QuitObjectOriented();}/*** 数三减一:普通方法*/public static void testCount3Quit() {// 初始化数组boolean[] bn = new boolean[100];for (int i = 0; i < bn.length; i++) {bn[i] = true;}int leftNum = bn.length; // 剩下的个数,剩下最后一个后停止int index = 0; // 下标标记,数完一圈后重新从0开始int countNum = 0; // 从0开始数,数到3后重新归零while (leftNum > 1) {if (bn[index] == true) {countNum++;if (countNum == 3) {bn[index] = false;countNum = 0;leftNum--;}}index++;if (index == bn.length)index = 0;}for (int i = 0; i < bn.length; i++) {if (bn[i] == true)System.out.println(i);}}/*** 数三减一:采用面向对象思想*/public static void testCount3QuitObjectOriented() {KidCircle kidCircle = new KidCircle(100);// System.out.println(kidCircle.count);// for (int i = 0; i < kidCircle.count; i++) {// System.out.println(kidCircle.kids[i]);// }int countNum = 0; // 从0开始数,数到3后重新归零Kid currentKid = kidCircle.first;while (kidCircle.count > 1) {countNum++;if (countNum == 3) {kidCircle.delete(currentKid);countNum = 0;}currentKid = currentKid.right;}System.out.println(kidCircle.first);System.out.println(kidCircle.last);}}/*** 定义小朋友类*/class Kid {int id;Kid left;Kid right;Kid(int id) {this.id = id;}@Overridepublic String toString() {return "Kid{" +"id=" + id +" left_id=" + left.id +" right_id=" + right.id +'}';}}/*** 定义Kid圆圈类*/class KidCircle {int count = 0; // 当前Kid圈总数Kid first; // 第一个小朋友Kid last; // 最后一个小朋友Kid[] kids;/*** 构造函数:构建小朋友手拉手圆圈* @param total*/KidCircle(int total) {kids = new Kid[total];for (int i = 0; i < total; i++) {Kid kid = add(i);kids[i] = kid;}}/*** 添加小朋友方法* @param index* @return*/public Kid add(int index) {index++;Kid kid = new Kid(index);if (index <= 0) {return null;} else if (index == 1) {first = kid;last = kid;kid.left = kid;kid.right = kid;} else {kid.left = last;kid.right = first;last.right = kid;first.left = kid;last = kid;}count++;return kid;}/*** 删除小朋友* @param kid*/public void delete(Kid kid) {if (count <= 0) {return;} else if (count == 1) {first = last = null;} else {kid.left.right = kid.right;kid.right.left = kid.left;if (kid == first) {first = kid.right;}if (kid == last) {last = kid.left;}}count--;}@Overridepublic String toString() {return "KidCircle{" +"count=" + count +", first=" + first +", last=" + last +'}';}}
