Skip to content

数组


数组的定义 ​

java
int[] a = {0, 1, 2};

提示:Java 中,数组定义时, [ ] 写在数据类型后(更规范),当然也可以写在变量名后 ​

基本介绍 ​

(1)数组的下标从 0 开始编号(第一个元素的下标) ​

(2)元素下标索引 = 元素物理位置 - 1 ​

(3)数组的本质:数组的类型是引用类型,底层是一个指针 ​

补充:Java 中的引用数据类型:数组,类,接口 ​

数组的底层存储机制 ​

基本介绍 ​

jvm 的内存

_____________   ——————————————————————————————
|            |  |  堆空间
|            |  |
|   栈空间   |  |
|            |  |______________________________
|            |  |   方法区
——————————————  |______________________________

(1)定义一个数组( int [ ] a ),此时数组默认指向 null,数组初始化时,jvm 内存发生变化,在堆空间中分配内存给数组,同时会返回一个地址 ​

(2)int [ ] a = new int [ 5 ],数组初始化完成,每一段内存空间对应一个空间地址(起始地址),此时 a 会引用内存空间的地址 ​

值传递 ​

底层实现:先把 a 的值拷贝一份,然后赋值给 b,两个值之间不会相互影响 ​

java
int a = 10;
int b = a;

引用传递 ​

底层实现:传递的内容是一个地址,即地址的引用发生变化,把 b 赋给 a 就表示 b 指向了 a 的引用(即 b 指向了 a 指向的内存空间),此时操作数组 b 等同于操作数组 a ​

java
int[] a = {1, 2, 3};
int[] b = a;
b[0] = 10;

数组的初始化 ​

静态初始化 ​

java
int[] a = {1, 2, 3};

动态初始化 ​

使用关键字 new。初始化时需要指定数组的类型和空间大小 ​

举例:int [ ] a = new int [ 5 ] ​

方式一:直接使用动态分配 ​

java
double scores[] = new double[5];

方式二:先声明,后分配 ​

java
double scores[];  // 此时 scores 是 null
scores = new double[5];

结合 scanner 录入数组值 ​

获取数组长度:数组名 . length( ) ​

java
import java.util.Scanner;
public class Main{
    public static void main(String[] args){
        // 创建扫描器
        Scanner scanner = new Scanner(System.in);
        int[] a = new int[5];
        // 动态录入
        for( int i = 0; i < a.length; i++){
            a[i] = scanner.nextInt();
        }
        // 打印测试
        for( int i = 0; i < a.length; i++){
            System.out.print(a[i] + " ");
        }
    }
}

使用细节 ​

(1)数组在初始化是就指定了类型,元素的数据类型需要相同,不可以混用 ​

错误案例 ​

int [ ] a = { 1, 2, 3.5 }; ​

错因分析:不可以把一个 double 赋值给 int ​

(2)数组定义后,如果没有初始化,会有默认值 ​

int: 0 ​

short: 0 ​

byte: 0 ​

long: 0 ​

float: 0.0 ​

double: 0.0 ​

char: \u0000 ​

boolean: false ​

String:null ​

(3) 数组的下标是从 0 开始的,元素下标索引 = 元素物理位置 - 1,警惕下标索引越界 ​

java
int[] arr = new int[5];  // 有效下标为 0 - 4

数组拷贝 ​

注意:区别于数组的地址传递,数组拷贝后两个数组独立,互不影响 ​

思路分析 ​

(1)首先创建一个新的数组,空间大小和原数组一致 ​

(2)for 遍历原数组,把原数组中的每一个值赋给新数组 ​

(3)打印新数组的值测试 ​

代码示例 ​

java
int[] a ={1, 2, 3};
int[] b = new int[a.length];

// 数组拷贝
for( int i = 0; i < a.length; i++){
    b[i] = a[i];
}

System.out.print("a数组的值:");
for( int i = 0; i < a.length; i++){
    System.out.print(a[i] + " ");
}

System.out.println("");

System.out.print("b数组的值:");
for( int i = 0; i < b.length; i++){
    System.out.print(b[i] + " ");
}


// 输出结果
a数组的值:1 2 3
b数组的值:1 2 3

翻转数组 ​

逆序赋值 ​

创建一个新数组 b,逆序拷贝数组 a,修改引用,让 a 指向 b 的引用,利用 Java 中的垃圾回收机制,自动回收数组 a,此时 a、b 指向同一个内存地址 ​

java
int[] a = {1, 2, 3};
int[] b = new int[a.length];
for( int i = a.length()-1,j = 0; i >= 0; i--,j++){
    b[j] = a[i];
}

a = b; //让 a 指向 b

for( int i = 0; i < b.lengt; i++){
    System.out.print(b[i] + " ");
}

System.out.println("");

for( int i = 0; i < a.length; i++){
    System.out.print(a[i] + " ");
}

双指针法 ​

建立头指针,尾指针,两指针相向而行(相撞指针),过程中交换两个指针指向的值,当两指针在中点相遇时,循环结束 ​

java
int[] a = {1, 2, 3};
for( int i = 0,j = a.length-1; i < a.length / 2; i++,j--){
    int temp = a[i];
    a[i] = a[j];
    a[j] = temp;
}

for( int i = 0; i < a.length; i++){
    System.out.print(a[i] + " ");
}
//输出: 3 2 1