1. 理解

1.2 数组是对象吗?

Note link

1.2 数组与引用

数组 : 一组相同任意类型的数据的组合, 便于统一管理.

由多个元素组成, 每个元素相当于是数组对象的属性.

数组中的要素(component)可以是任何数据类型,包括基本数据类型和引用数据类型; 数组属引用类型,数组型数据是对象(object),数组中的每个要素相当于该对象的成员变量.

arr[i], i0arr.length - 1.

其他引用则会出现 ArrayIndexOutOfBoundsEception.

1.3 长度属性

arr.lengthfinal 常量类型, 数组创建时就确定, 无法更改.

数组一旦创建, 长度无法更改.

1.4 遍历

  1. // 经典 for 循环
  2. for (int i = 0; i < arr.length; i++){
  3. System.out.println(arr[i]);
  4. }
  5. // 增强 for 循环 foreach, 只读
  6. for (int i : arr){
  7. System.out.println(i);
  8. }
  9. // Invoke Array Class's method
  10. Arrays.toSring(arr);

2. 一维数组声明与初始化

2.1 声明

数组声明 : 元素数据类型[] 数组名;, 声明数组时不能指定其长度(数组中元素的数), 例如 : int a[5]; //非法.
数组创建 : 数组名 = new 元素数据类型[元素个数];

  1. int a[];
  2. int[] a1;
  3. double b[];
  4. Mydate[] c; //对象数组

2.2 动态初始化

动态初始化 : 声明与赋值分开

  1. int[] arr = new int[3];
  2. arr[0] = 3;
  3. arr[1] = 9;
  4. arr[2] = 8;
  5. ---
  6. MyDate dates[];
  7. dates = new MyDate[3];
  8. dates[0] = new MyDate(22, 7, 1964);
  9. dates[1] = new MyDate(1, 1, 2000);
  10. 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 引用数据类型数组内存解析

数组 - 图1
以如下代码为例:

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){}