数组 | 我的日常分享

数组

数组

一、为什么使用数组

如何存储100名学生的成绩?

  • 方法:使用变量存储,重复声明100个double类型的变量。
  • 缺点:麻烦,重复操作过多。

如何让100名学生成绩全部+1?

  • 方法:100个变量重复相同的操作,直至全部完毕。
  • 缺点:无法进行统一的操作。

通过上面的两个场景,很清楚地能了解到数组可以简化、统一操作。

二、数组的概念

  • 概念:一组连续的存储空间,存储多个相同数据类型的值。

  • 数组的创建

    1
    2
    3
    4
    5
    6
    public class TestCreateArray{
    public static void main(String[] args){
    //声明int数组类型变量a
    int[] a = new int[5];//分配长度为5的连续空间
    }
    }

    image-20220122192849627

  • 数组的组成

    image-20220122193131190

    • 数组中的每个数据格被称为“数组元素”。
    • 对每个元素进行赋值或取值的操作被称为“元素的访问”。
    • 访问元素时,需要使用“下标”(从0开始,依次+1,自动生成)
    • 访问的语法:数组名[下标];例如,存:a[0]=10;取:a[0]
  • 数组的使用

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    public class TestCreateArray{
    public static void main(String[] args){
    int[] a = new int[5];//创建数组
    //依次赋值
    a[0]=11;
    a[1]=22;
    a[2]=33;
    a[3]=44;
    a[4]=55;
    //依次取值
    System.out.println(a[0]);
    System.out.println(a[1]);
    System.out.println(a[2]);
    System.out.println(a[3]);
    System.out.println(a[4]);
    }
    }

    运行结果:

    image-20220122193759800

  • 下标的范围

    有效下标访问:0~数组长度-1

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    public class TestCreateArray{
    public static void main(String[] args){
    int[] a = new int[5];//创建数组
    //依次赋值
    a[0]=11;
    a[1]=22;
    a[2]=33;
    a[3]=44;
    a[4]=55;
    //依次取值
    System.out.println(a[0]);
    System.out.println(a[1]);
    System.out.println(a[2]);
    System.out.println(a[3]);
    System.out.println(a[4]);
    System.out.println(a[5]);//无效下标,数组越界
    }
    }

    运行结果:

    当运行到这一行代码的时候,出现数组下标溢出异常。

    image-20220122194042829

  • 数组的遍历

    从头到尾,逐一对数组的每个元素进行访问。数组名.length可动态获得数组长度。

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    public class TestVisitArray{
    public static void main(String[] args){
    int[] a = new int[5];
    a[0]=11;
    a[1]=22;
    a[2]=33;
    a[3]=44;
    a[4]=55;
    //数组遍历
    for(int i=0;i<a.length;i++){
    System.out.println(a[i]);
    }
    }
    }

    运行结果:

    image-20220122194627853

  • 数组的默认值

    在没有为数组元素赋值的情况下,依旧可以正确访问。整数数组的默认值为0

    1
    2
    3
    4
    5
    整数:0
    小数:0.0
    字符:\u0000
    布尔:false
    其他(引用数据类型):null
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    public class TestDefaultValue{
    public static void main(String[] args){
    int[] a = new int[5];
    for(int i=0;i<a.length;i++){
    System.out.println(a[i]);
    }
    double[] b = new double[5];
    for(int i=0;i<b.length;i++){
    System.out.println(b[i]);
    }
    char[] c = new char[5];
    for(int i=0;i<c.length;i++){
    System.out.println("#"+c[i]+"#");
    }
    boolean[] d = new boolean[5];
    for(int i=0;i<d.length;i++){
    System.out.println(d[i]);
    }
    String[] e = new String[5];
    for(int i=0;i<e.length;i++){
    System.out.println(e[i]);
    }
    }
    }

    运行结果:

    image-20220122195541259

三、数组创建的几种方式

  • 先声明、再分配空间

    1
    2
    数据类型[] 数组名;
    数组名 = new 数据类型[长度];
  • 声明并分配空间

    1
    数据类型[] 数组名 = new 数据类型[长度];
  • 声明并赋值(繁琐)

    1
    2
    3
    4
    5
    6
    数据类型[] 数组名 = new 数据类型[]{value1,value2,value3,...};
    /*
    这种方式可先声明后赋值
    数据类型[] 数组名;
    数组名 = new 数据类型[]{value1,value2,value3,...};
    */
  • 声明并赋值(简单)

    1
    2
    3
    4
    5
    6
    数据类型[] 数组名 = {value1,value2,value3,...};
    /*
    注意这种方式不可先声明后赋值
    数据类型[] 数组名;
    数组名 = {value1,value2,value3,...};
    */

案例1:给定一个整数数组,统计数组中所有元素的平均值。

1
2
3
4
5
6
7
8
9
10
11
public class TestAvg{
public static void main(String[] args){
int[] arr = {10,20,30,40};
int sum = 0;
for(int i=0;i<arr.length;i++){
sum = sum + arr[i];
}
int avg = sum/arr.length;
System.out.println("平均值为:"+avg);
}
}

运行结果:

image-20220122224541997

案例2:给定一个整数数组,读入一个整数n,如果n在数组中存在,输入下标,不存在则输出-1

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
import java.util.Scanner;
public class TestArrIndex{
public static void main(String[] args){
int[] arr = {10,20,30,40,50};
Scanner input = new Scanner(System.in);
int num = input.nextInt();
int i=0;
for(i=0; i<arr.length; i++){
if(arr[i] == num){
System.out.println(num+"在数组中的下标为:"+i);
break;
}
}
//不存在
if(i == arr.length){
System.out.println("-1");
}
}
}

运行结果:

image-20220122225322721

四、数组的扩容

  • 创建数组时,必须显示指定长度,并在创建之后不可更改长度。

  • 扩容的思路:

    1. 创建大于原数组长度的新数组。
    2. 将原数组中的元素依次复制到新数组中。

    image-20220123112910948

  • 复制的方式

    1. 循环将原数组中所有元素逐一赋值给新数组。

    2. System.arraycopy(原数组,原数组起始,新数组,新数组起始,长度);

      从原数组起始位置复制长度个元素,从新数组起始位置开始赋值给新数组。

    3. java.util.Arrays.copyOf(原数组,新数组长度);//返回带有原值的新数组。

案例1:循环赋值

1
2
3
4
5
6
7
8
9
10
11
12
public class TestArrCopy{
public static void main(String[] args){
int[] oldArr = {11,22,33,44,55};
int[] newArr = new int[9];
for(int i=0;i<oldArr.length;i++){
newArr[i] = oldArr[i];
}
for(int i=0;i<newArr.length;i++){
System.out.println(newArr[i]);
}
}
}

运行结果:

image-20220123113923117

案例2:System.arraycopy();

1
2
3
4
5
6
7
8
9
10
public class TestArrCopy{
public static void main(String[] args){
int[] oldArr = {11,22,33,44,55};
int[] newArr = new int[9];
System.arraycopy(oldArr,0,newArr,0,5);
for(int i=0;i<newArr.length;i++){
System.out.println(newArr[i]);
}
}
}

运行结果:

image-20220123120214956

案例3:java.util.Arrays.copyOf(原数组,新数组长度);

这个工具方法会根据指定的新数组长度会初始化指定长度的数组,并将原数组的值赋给新数组后,返回新数组。

1
2
3
4
5
6
7
8
9
10
11
12
import java.util.Arrays;

public class TestArrCopy{
public static void main(String[] args){
int[] oldArr = {11,22,33,44,55};
int[] newArr;
newArr = Arrays.copyOf(oldArr,6);
for(int i=0;i<newArr.length;i++){
System.out.println(newArr[i]);
}
}
}

运行结果:

image-20220123121105839

数组作为引用类型之一,其变量中存储的是数组的地址。

五、数组类型的参数

1
2
3
4
5
6
7
8
9
10
11
public class TestArrayParameter{
public static void main(String[] args){
int[] arr = {10,20,30,40,50};
printArr(arr);
}
public static void printArr(int[] oneArray){
for(int i=0;i<oneArray.length;i++){
System.out.println(oneArray[i]);
}
}
}

假设arr的地址为0x0000A001;参数传入后oneArray的地址为0x0000A001

printArr方法调用时,将arr中的地址赋给了oneArray,此时二者指向同一个数组。

运行结果:

image-20220123140500410

传递参数时,基本类型传递的是变量中的值,引用类型传递的是变量中的地址。

六、数组类型的返回值

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class TestReturnValue{
public static void main(String[] args){
int[] arr1 = {10,20,30,40,50};
int[] arr2 = expand(arr1);
for(int i=0;i<arr2.length;i++){
System.out.println(arr2[i]);
}
}
public static int[] expand(int[] oldArr){
int[] newArray = new int[oldArr.length*2];
for(int i=0;i<oldArr.length;i++){
newArray[i]=oldArr[i];
}
return newArray;
}
}

假设arr1的地址为0x0000a001,调用函数expand传给oldArr的地址为0x0000a001,在函数内部给newArraynew了一个新的地址,并将oldArr的值逐个赋给newArray,假设newArray的地址为0x0000a002,函数的返回值也是这个,于是arr2的值也是0x0000a002

运行结果:

image-20220123142427174

调用数组类型返回值的方法时,方法执行后,返回的是数组的地址。

七、可变长参数

概念:可接受多个同类型的实参,个数不限,使用方式与数组相同。

语法:数据类型...形参名必须定义在形参列表的最后,且只能有一个。

1
2
3
4
5
6
7
8
9
10
11
public class variableArguments{
public static void main(String[] args){
myPrints("hello",30,'a',10,20,30,40,50,60);
}
public static void myPrints(String str,int n1,char c1,int...arrInt){
System.out.println(str+" "+n1+" "+c1);
for(int i=0;i<arrInt.length;i++){
System.out.println(arrInt[i]);
}
}
}

运行结果:

image-20220123143438143

八、Arrays 类

java.util.Arrays 类能方便地操作数组,它提供的所有方法都是静态的。

查看文档

image-20220124144411672

九、二维数组

概念:一维数组中的一维数组;数组中的元素,还是数组。

1.二维数组的赋值

1
2
3
4
5
6
7
8
9
10
public class Test2DArray{
public static void main(String[] args){
int[][] array = new int[3][5];
array[0][0] = 10;
array[1][3] = 20;
array[1][4] = 30;
array[2][2] = 40;
array[2][3] = 50;
}
}

image-20220123151939406

2.二维数组的访问

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
public class Test2DArray{
public static void main(String[] args){
int[][] array = new int[3][5];
array[0][0] = 10;
array[1][3] = 20;
array[1][4] = 30;
array[2][2] = 40;
array[2][3] = 50;
for(int i=0;i<array.length;i++){
for(int j=0;j<array[i].length;j++){
System.out.print(array[i][j]+" ");
}
System.out.println();
}
}
}

运行结果:

image-20220123152422330

3.二维数组创建的几种方式

动态初始化

1
2
3
数据类型 数组名[][] = new 数据类型[m][n]
数据类型[][] 数组名 = new 数据类型[m][n]
数据类型[] 数组名[] = new 数据类型[m][n]
  • 先声明,再分配空间:

    1
    2
    数据类型[][] 数组名;
    数组名 = new 数据类型[高维长度][多维长度];
  • 声明并分配空间:

    1
    数据类型[][] 数组名 = new 数据类型[高维长度][多维长度];

静态初始化

1
数据类型 [][] 数组名= {{元素1,元素2....},{元素1,元素2....},{元素1,元素2....}.....};

静态初始化可用于不规则二维数组的初始化

  • 声明并赋值

    1
    2
    3
    数据类型[][] 数组名 = new 数据类型[][]{{v1,v2,v3},{v4,v5,v6}};

    数据类型[][] 数组名 = {{v1,v2,v3},{v4,v5,v6}};