1. 理解
1.2 数组是对象吗?
1.2 数组与引用
数组 : 一组相同任意类型的数据的组合, 便于统一管理.
由多个元素组成, 每个元素相当于是数组对象的属性.
数组中的要素(component)可以是任何数据类型,包括基本数据类型和引用数据类型; 数组属引用类型,数组型数据是对象(object),数组中的每个要素相当于该对象的成员变量.
arr[i]
, i
从 0
到 arr.length - 1
.
其他引用则会出现 ArrayIndexOutOfBoundsEception
.
1.3 长度属性
arr.length
是 final
常量类型, 数组创建时就确定, 无法更改.
数组一旦创建, 长度无法更改.
1.4 遍历
// 经典 for 循环
for (int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
// 增强 for 循环 foreach, 只读
for (int i : arr){
System.out.println(i);
}
// Invoke Array Class's method
Arrays.toSring(arr);
2. 一维数组声明与初始化
2.1 声明
数组声明 : 元素数据类型[] 数组名;
, 声明数组时不能指定其长度(数组中元素的数), 例如 : int a[5]; //非法
.
数组创建 : 数组名 = new 元素数据类型[元素个数];
int a[];
int[] a1;
double b[];
Mydate[] c; //对象数组
2.2 动态初始化
动态初始化 : 声明与赋值分开
int[] arr = new int[3];
arr[0] = 3;
arr[1] = 9;
arr[2] = 8;
---
MyDate dates[];
dates = new MyDate[3];
dates[0] = new MyDate(22, 7, 1964);
dates[1] = new MyDate(1, 1, 2000);
dates[2] = new MyDate(22, 12, 1964);
2.3 静态初始化
静态初始化: 适用于数据量小, 且元素值确定.
方式一: int[] arr = new int[]{1, 2, 3};
方式二: int[] arr = {1, 2, 3, 4};
. 使用受限, 声明和初始化必须在同一条语句内.
静态初始化的 int[] a = {3,9,8};
只能在声明的同时这样, 如果声明后, 再 a = {3, 9, 8};
则会报错, 只能 a = new in[]{3, 9, 8};
.
2.4 默认初始化
数组是引用类型, 它的元素相当于类的成员变量, 因此数组一经分配空间, 其中的每个元素也被按照成员变量同样的方式被隐式初始化. 例如 :
int a[]= new int[5];
System.out.println(a[3]); //a[3]的默认值为0
- 对于基本数据类型而言,默认初始化值各有不同.
- 对于引用数据类型而言,默认初始化值为null(注意与0不同!).
3. 内存解析
3.1 基本数据类型数组代码解析
以以下代码为例:
public class ArrayTest {
public static void main(String[] args) {
// 声明 : 元素数据类型[] 数组名;
int[] arr; // 此时没有数组对象存在的.
// 创建 : new 元素数据类型[元素个数];
arr = new int[5]; // 在 GC 区中创建一个元素有 5 个的 int 型数组. 数组对象创建好以后, 所有元素都有缺省值 0
// 数组元素的定位(访问), 通过首地址(数组名)[偏移量(也称为下标, 索引, 脚标)]
// 每个元素都是一个小变量.
arr[2] = 4;
arr[0] = 3;
arr[arr[0]] = 1;
arr[arr[2]] = 5;
// 分析每个元素的值
System.out.println(arr[0]); // 3
System.out.println(arr[1]); // 0
System.out.println(arr[2]); // 4
System.out.println(arr[3]); // 1
System.out.println(arr[4]); // 5
}
}
3.2 引用数据类型数组内存解析
以如下代码为例:
class MyDate {
private int year;
private int month;
private int day;
public MyDate() {}
public MyDate(int year, int month, int day) {
this.year = year;
this.month = month;
this.day = day;
}
public String say() {
return year + "年" + month + "月" + day + "日";
}
}
class ArrayTest6 {
// 引用数组, 也称为对象数组, 本质上数组中保存的是地址.
public static void main(String[] args) {
MyDate[] arr; // 此时只是在栈中有一个局部的小引用
arr = new MyDate[4]; // 4 空洞
arr[0] = new MyDate(2001, 3, 4);
arr[1] = new MyDate(2008, 8, 8);
arr[2] = new MyDate(1992, 4, 10);
// 之前有空洞 : 引用数组中为null的元素, 空洞很危险, 会出空指针异常.
arr[3] = new MyDate(0, 0, 0);
// 遍历数组
for (int i = 0; i < arr.length; i++) {
if (arr[i] != null) {
System.out.println(arr[i].say()); // 空指针异常 : 出现空指针通常会有一个.操作
} else {
System.out.println(arr[i]); // 空指针异常 : 出现空指针通常会有一个.操作
}
}
}
}
4. 数组的基本用法
Get a random-value int array by below code:
public static int[] getIntArray(int n){
int[] arr = new int[n];
for (int i = 0; i < arr.length; i++) {
// get fixed seed random number: 0, 5, 8, 14, 2, 7, 11, 16, 4, 9
arr[i] = new Random().nextInt(20);
}
return arr;
}
4.1 Travel and reverse the array
int[] arr = getIntArray(20);
System.out.println(Arrays.toString(arr));
// classic for loop
for (int i = 0; i < arr.length; i++) {
int tmp = arr[i];
System.out.print(tmp + " ");
}
System.out.println();
// foreach, Enhanced for loop, read only
// shortcuts: iter
for (int tmp : arr) {
System.out.print(tmp + " ");
}
System.out.println();
// Reverse the array
for (int i = 0; i < arr.length / 2; i++) {
int temp = arr[i];
arr[i] = arr[arr.length - 1 - i];
arr[arr.length - 1 - i] = temp;
}
System.out.println(Arrays.toString(arr));
4.2 Get the max/min value of the array
int[] arr = getIntArray(20);
System.out.println(Arrays.toString(arr));
4.2.1 By value variable
// Get the max/min value of the array.
System.out.println("Find by using value variable");
System.out.println("Get max/min value of array:");
int max = arr[0];
int min = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {max = arr[i];}
if (arr[i] < min) {min = arr[i];}
}
System.out.println("max:" + max);
System.out.println("min:" + min);
// Get the max/min number in the array that is divisible by 7.
System.out.println("Get the max/min number in the array that is divisible by 7:");
// Min integer 0x80000000, max integer 0x7ffffff.
int max7 = Integer.MIN_VALUE;
int min7 = Integer.MAX_VALUE;
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 7 == 0) {
if (arr[i] > max7) {max7 = arr[i];}
if (arr[i] < min7) {min7 = arr[i];}
}
}
if (max7 == Integer.MIN_VALUE) {
System.out.println("There's no value that's divisible by 7 in the array.");
} else {
System.out.println("max: " + max7);
System.out.println("min: " + min7);
}
4.2.2 By index
// Get the max/min value of the array.
System.out.println("Find by using index");
System.out.println("Get max/min value of array:");
int maxIndex = 0;
int minIndex = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] > arr[maxIndex]) {maxIndex = i;}
if (arr[i] < arr[minIndex]) {minIndex = i;}
}
System.out.println("max: " + arr[maxIndex]);
System.out.println("min: " + arr[minIndex]);
// Get the max/min number in the array that is divisible by 7.
System.out.println("Get the max/min number in the array that is divisible by 7:");
int maxIndex7 = -1;
int minIndex7 = -1;
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 7 == 0){
if (maxIndex7 == -1 || arr[i] > arr[maxIndex7]) {maxIndex7 = i;}
if (minIndex7 == -1 || arr[i] < arr[minIndex7]) {minIndex7 = i;}
}
}
if (maxIndex7 == -1){
System.out.println("There's no value that's divisible by 7.");
} else {
System.out.println("max: " + arr[maxIndex7]);
System.out.println("min: " + arr[minIndex7]);
}
4.3 Larger/smaller array capacity
int[] arr = getIntArray(10);
// 0, 5, 8, 14, 2, 7, 11, 16, 4, 9
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
4.3.1 Create a smaller array index between [0, arr.length / 2]
int[] newArr = new int[arr.length / 2];
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
arr = newArr;
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
4.3.2 Create a larger array index between [0, (int) (arr.length * 1.5)]
newArr = new int[(int)(arr.length * 1.5)];
for (int i = 0; i < arr.length; i++) {
newArr[i] = arr[i];
}
arr = newArr;
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
4.4 Get a conditional subarray
Get a new array which contains the odd number in original array.
int[] arr = getIntArray(20);
for (int i : arr) {
System.out.print(i + " ");
}
System.out.println();
// Get a new array which contains the odd number in original array.
int[] newArr = new int[arr.length];
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 2 == 1) {
newArr[count++] = arr[i];
}
}
newArr = Arrays.copyOfRange(newArr, 0, count);
System.out.println(Arrays.toString(newArr));
5. 多维数组
5.1 声明与创建
5.1.1 声明
二维数组 : 数组的数组, 它的元素是子数组, 所以它的length是有几个子数组的意思
声明方式 :
int[][] a
int[] a[]
int a[][]
下列数组定义正确的是:
int[][] a = new int[][]; 不对, new 至少第一维中长度要给定
int b[8][8] = new int[][]; 不对, 声明时绝对不能给长度
int c[][] = new int[8][]; 对
int[] d [] = new int[5][5]; 对
int[][] a = new int [5][4]; 对
5.1.2 创建与赋值
动态方式:
int[][] arrarr = new int[3][];
arrarr[0] = new int[] {1, 3, 4};
arrarr[1] = new int[] {};
arrarr[2] = new int[4];
// 1, 3, 4
// 空
// 0, 0, 0, 0
静态方式 1: 比较灵活, 可以适用于声明和赋值分开的情况
int[][] arrarr2;
arrarr2 = new int[][] {{1, 9}, {7, 3, 4}, {8, 2, 5, 4, 1}};
System.out.println(arrarr2[1].length); // 3
静态方式2: 这种写法只适用于声明和初始化在同一条语句 上的情况
int[][] arrarr3 = {{1,2}, {3, 4, 5}};
5.2 遍历
二维数组遍历:
Random random = new Random();
int[][] arrarr = new int[10][];
for (int i = 0; i < arrarr.length; i++) {
arrarr[i] = new int[i + 1]; //
for (int j = 0; j < arrarr[i].length; j++) {
arrarr[i][j] = random.nextInt();
}
}
// 遍历
for (int i = 0; i < arrarr.length; i++) {
for (int j = 0; j < arrarr[i].length; j++) {
System.out.print(arrarr[i][j] + " ");
}
System.out.println();
}
5.3 求最值
找出二维数组最大值:
int max = arrarr[0][0];
for (int[] child : arrarr) {
for (int tmp : child) {
if (tmp > max) {
max = tmp;
}
}
}
System.out.println("max = " + max)
5.4 杨辉三角
打印一个 n 层杨辉三角:
int[][] yanghui = new int[n][];
for (int i = 0; i < yanghui.length; i++) {
yanghui[i] = new int[i + 1]; // 每行的数据个数和行数相关
for (int j = 0; j < yanghui[i].length; j++) {
yanghui[i][0] = 1;
yanghui[i][i] = 1;
if (j > 0 && j < i) {
yanghui[i][j] = yanghui[i-1][j-1] + yanghui[i-1][j];
}
}
}
for (int[] child : yanghui) {
for (int tmp : child) {
System.out.print(tmp + " ");
}
System.out.println();
}
6. 可变参数
variable arguments
, 参数个数可变
① 一个方法中最多一个可变参数, 并且只能放在参数列表最后.
② 可变参数本质相当于于数组, 编译时编译器将可变参数编译为对应的数组, 故不能共存:
int avg(int[] values){}
int avg(int... values){}