Saul's blog Saul's blog
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)

Saul.J.Wu

立身之本,不在高低。
首页
后端
分布式
前端
更多
分类
标签
归档
友情链接
关于
GitHub (opens new window)
  • Java入门基础

    • 计算机常识

    • Java语言概述

    • 基本语法

    • 数组

      • 数组
        • 数组(Array)的概述
        • 数组的常见概念
        • 数组的特点
        • 数组的分类
        • 一维数组
          • 声明和初始化
          • 调用数组
          • 数组长度
          • 遍历数组
          • 默认初始化值
          • 数组的内存解析
          • 练习1
          • 练习2
        • 多维数组
          • 声明和初始化
          • 调用数组
          • 数组长度
          • 遍历数组
          • 默认初始化值
          • 内存解析
          • 练习1
          • 练习2
          • 练习3
        • 数组中涉及的常见算法
        • 数值型相关练习
        • 数组的复制
        • 数组的反转操作
        • 数组中常见的异常
          • 数组脚标越界异常(ArrayIndexOutOfBoundsException)
          • 空指针异常(NullPointerException)
      • 排序算法
      • Arrays工具类
    • 面向对象

    • 异常处理

  • Java核心基础

  • 设计模式

  • Web开发

  • SpringBoot

  • 微服务

  • Elasticsearch

  • 运维

  • 后端
  • Java入门基础
  • 数组
SaulJWu
2020-12-07

数组

# 数组(Array)的概述

是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。

# 数组的常见概念

  • 数组名
  • 下标(或索引或角标)
  • 元素
  • 数组的长度

# 数组的特点

  • 数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。
  • 创建数组对象在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址
  • 数组的长度一旦确定,就不能修改。
  • 数组是有序排列的。可以通过下标的方式指定位置的元素。

还有一种不是连续空间的,叫列表,后面会提到。

数组的长度不能修改,如果要增加元素只能重新开辟内存空间,把原来的元素拷贝进去,追加新元素。

# 数组的分类

按照维度:

一维数组、二维数组、三维数组……

按照元素的数据类型分类:

基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)

# 一维数组

接下来我们将学习

  1. 一维数组的声明和初始化
  2. 如何调用数组的指定位置和元素
  3. 如何获取数组的长度
  4. 如何遍历数组
  5. 数组元素的默认初始化值
  6. 数组的内存解析

# 声明和初始化

# 语法格式

数据类型[] 变量名;
变量名 = new 数据类型[]{...}
1
2
数据类型[] 变量名 = new 数据类型[]{...}
1
数据类型 变量名[] = new 数据类型[]{...}
1
数据类型[] 变量名 = {...}
1

还有一种直接将引用指向某个引用

# 静态初始化

数组的初始化和数组的元素的赋值操作同时进行,称为数组的静态初始化。

声明:

int[] ids;
1

初始化:

ids = new int[]{123,124,125}
1

数组是引用数据类型,一定要用new

当然也可以声明和初始化一起写:

int[] ids = new int[]{123,124,125}
1

# 动态初始化

数组的初始化和数组的元素的赋值操作分开进行,称为数组的动态初始化。

String[] names = new String[5]
1

在实际业务场景中,有时候我们不能确定元素的赋值,所以需要先声明后面逻辑操作获得赋值。

# 错误的写法

int[] arr1 = new int[];
int[5] arr2 = new int[5];
int[] arr3 = new int[3]{1,2,3};
1
2
3

# 调用数组

如何调用数组的指定位置和元素?通过下标(索引或角标)的方式调用。

数组的下标(或索引) 是从0开始的,到数组的长度-1结束。

例如:

String[] names = new String[5]
names[0] = "名字一";
names[1] = "名字二";
names[2] = "名字三";
names[3] = "名字四";
names[4] = "名字五";
1
2
3
4
5
6

当你尝试操作第6个下标,会发生数组越界

names[5] = "名字六";
1

编译虽然能通过,但是程序会报java.lang.ArrayIndexOutOfBoundsException

因为在初始化时,数组的长度只有5,当你去访问第6个,自然会数组越界。

# 数组长度

每个数组都有个length属性,例如上面案例中,可以这样访问:

System.out.println(names.length)
1

将会返回5。

# 遍历数组

还是用上面names数组:

for(int i=0;i<names.length-1;i++){
    System.out.println(names[i]);
}
1
2
3

# 默认初始化值

如果数组初始化时,元素不指定值,会根据数组类型产生默认值。

  • 整型,默认值为:0
  • 浮点型,默认值为:0.0
  • char型,默认值为:0或‘\u0000’,而非‘0’
  • boolean型,默认值为:false
  • 如果元素是引用数据类型,默认值为:null

数组元素是int类型

package arrayTest;

public class Demo1 {
    public static void main(String[] args) {
        int[] arr = new int[4];
        for (int i = 0; i < arr.length; i++) {
            System.out.println(arr[i]);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
0
0
0
0
1
2
3
4

数组元素是short类型

short[] arr2 = new short[4];
for (int i = 0; i < arr2.length; i++) {
    System.out.println(arr2[i]);
}
1
2
3
4
0
0
0
0
1
2
3
4

数组元素是float类型

float[] arr3 = new float[4];
for (int i = 0; i < arr3.length; i++) {
System.out.println(arr3[i]);
}
1
2
3
4
0.0
0.0
0.0
0.0
1
2
3
4

数组元素是char类型

char[] arr4 = new char[4];
for (int i = 0; i < arr4.length; i++) {
    System.out.println("---" + arr4[i] + "***");
    if(arr4[i] == 0){
        System.out.println("默认是0或‘\\u0000’,而非‘0’");
    }
}
1
2
3
4
5
6
7
--- ***
默认是0或‘\u0000’,而非‘0’
--- ***
默认是0或‘\u0000’,而非‘0’
--- ***
默认是0或‘\u0000’,而非‘0’
--- ***
默认是0或‘\u0000’,而非‘0’
1
2
3
4
5
6
7
8

数组元素是boolean类型

boolean[] arr5 = new boolean[4];
for (int i = 0; i < arr5.length; i++) {
System.out.println(arr5[i]);
}
1
2
3
4
false
false
false
false
1
2
3
4

数组元素是引用数据类型

String[] arr6 = new String[4];
for (int i = 0; i < arr6.length; i++) {
    System.out.println(arr6[i]);
    if (arr6[i] == null) {
        System.out.println("引用数据类型,默认值为:null");
    }
}
1
2
3
4
5
6
7
null
引用数据类型,默认值为:null
null
引用数据类型,默认值为:null
null
引用数据类型,默认值为:null
null
引用数据类型,默认值为:null
1
2
3
4
5
6
7
8

# 数组的内存解析

其实new关键字,就是面向对象的用法。

  • 内存的结构

内存的规范首次是JVM的书籍中提到,不同JDK中当中,内存的结构稍微有所区别。

# 简化图

内存中结构中,可以将内存划分为:

  • 栈(stack):局部变量

  • 堆(heap):new出来的结构:对象、数组

  • 方法区(method area)

    • 常量池
    • 静态域

image-20201207120317580

代码解析:

int[] arr = new int[]{1,2,3};
1

image-20201207123500421

# 练习1

公寓合租招租4个月,1550元/月(水电煤公摊,网费35元/月),由于屋内均是IT人士,所以他的联系方式为:

8,2,1,0,3
2,0,3,2,4,0,1,3,2,2,3
1
2

那么他的联系方式是?

package arrayTest;

public class Demo2 {
    public static void main(String[] args) {
        int[] arr = new int[]{8, 2, 1, 0, 3};
        int[] index = new int[]{2, 0, 3, 2, 4, 0, 1, 3, 2, 2, 3};
        String tel = "";
        for (int i = 0; i < index.length; i++) {
            tel += arr[index[i]];
        }
        System.out.println("联系方式为:" + tel);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
联系方式为:18013820110
1

# 练习2

image-20201207125849299

package arrayTest;

import java.util.Scanner;

public class Demo3 {
    public static void main(String[] args) {
        int max = 0;
        Scanner scan = new Scanner(System.in);
        // 获取学生人数
        System.out.println("请输入学生的人数:");
        int nums = scan.nextInt();
        int[] scores = new int[nums];
        //获取学生分数
        System.out.println("请以此输入" + nums + "个学生的成绩:");
        for (int i = 0; i < scores.length; i++) {
            //给数组中的元素赋值
            scores[i] = scan.nextInt();
            if (max < scores[i]) {
                //获取最高分
                max = scores[i];
            }
        }
        //遍历数组,评级
        for (int i = 0; i < scores.length; i++) {
            String rate = "";
            if (scores[i] >= max - 10) {
                rate = "A";
            } else if (scores[i] >= max - 20) {
                rate = "B";
            } else if (scores[i] >= max - 30) {
                rate = "C";
            } else {
                rate = "D";
            }
            System.out.println("学号:" + i + "的学生成绩为:" + scores[i] + ",评级为:" + rate);
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38

# 多维数组

Java语言里提供了支持多维数组的语法。多维数组又以二维数组居多。如果说可以把一堆数组当成几何中的线性图形,那么二维数组就相当于一个表格。对于二维数组的理解,我们可以看成一维数组又作为另一对堆一维数组的元素而存在。其实,从数组底层的运行机制来看,其实没有多维数组。

接下来我们将学习

  1. 二维数组的声明和初始化
  2. 如何调用数组的指定位置和元素
  3. 如何获取数组的长度
  4. 如何遍历数组
  5. 数组元素的默认初始化值
  6. 数组的内存解析

# 声明和初始化

# 语法格式

数据类型[][] 变量名 = new 数据类型[][]{{……},{……},{……}}
1
数据类型[] 变量名[] = new 数据类型[][]{{……},{……},{……}}
1
数据类型 变量名[][] = new 数据类型[][]{{……},{……},{……}}
1
数据类型[][] 变量名 = {{……},{……},{……}}
1

# 静态初始化

//一维数组
int[] arr = new int[]{1,2,3};
//二维数组
int[][] arr2 = new int[][]{{1,2,3},{4,5},{7,8,9}};
1
2
3
4

# 动态初始化

String[][] arr3 = new String[3][2];
String[][] arr4 = new String[3][];
1
2

# 错误的写法

String[][] arr5 = new String[][];
String[][] arr6 = new String[][3];
String[][] arr7 = new String[4][3]{{1,2,3},{4,5},{7,8,9}};
1
2
3

# 调用数组

//二维数组
int[][] arr = new int[][]{{1,2,3},{4,5},{7,8,9}};
//访问外层元素
System.out.println(arr[0]);
//访问内层元素
System.out.println(arr[0][1]); //2
1
2
3
4
5
6

同样如果数组下标越界,也会报java.lang.ArrayIndexOutOfBoundsException

# 数组长度

//二维数组
int[][] arr = new int[][]{{1,2,3},{4,5},{7,8,9}};
//外层元素长度
System.out.println(arr.length);//3
//内层元素长度
System.out.println(arr[1].length);//2
1
2
3
4
5
6

# 遍历数组

关于多维数组的遍历,二维就二层循环,n层就n层循环。

package arrayTest;

public class Demo1 {
    public static void main(String[] args) {
        int[][] arr = new int[][]{{1,2,3},{4,5},{7,8,9}};
        for (int i = 0; i < arr.length; i++) {
            for(int j=0;j<arr[i].length;j++){
                System.out.print(arr[i][j]);
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13

# 默认初始化值

二维数组分为外层元素和内层元素。

外层元素是一个对象,内层元素是才是具体值。

int[][] arr = new int[4][3];
System.out.println(int[0]);//内存地址
System.out.println(int[0][0])//0 一个整形
1
2
3

外层元素是指向一个对象的内层地址,代表一个对象。

内层元素是指向具体值。具体值的默认值跟一维数组的一样。

int[][] arr = new int[4][];
1

外层元素是指向一个对象的内层地址,但是并没有指向任何对象,所以是null。

内层元素还没被创建,所以也不能访问。

# 内存解析

二维数组的内存解析

image-20201207151525844

image-20201207152116844

# 练习1

image-20201207152216786

通过图像可知,存在一个多维数组

package arrayTest;

import java.util.Scanner;

public class Demo4 {
    public static void main(String[] args) {
        int total = 0;
        int[][] arr = new int[][]{{3, 5, 8}, {12, 9}, {7, 0, 6, 4}};
        for (int i = 0; i < arr.length; i++) {
            for (int j = 0; j < arr[i].length; j++) {
                total += arr[i][j];
            }
        }
        System.out.println(total);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

结果是54

# 练习2

image-20201207152620975

a no,

b yes,

c no

d no

e yes

f no

# 练习3

image-20201207152827198

package arrayTest;

public class Demo5 {
    public static void main(String[] args) {
        int[][] arr = new int[10][];
        for (int i = 0; i < arr.length; i++) {
            System.out.print("[" + i + "] ");
            arr[i] = new int[i+1];
            for (int j = 0; j < arr[i].length; j++) {
                if (j == 0 || j == arr[i].length - 1) {
                    arr[i][j] = 1;
                } else if (i > 1) {
                    arr[i][j] = arr[i - 1][j] + arr[i - 1][j - 1];
                }

                System.out.print(arr[i][j] + " ");
            }
            System.out.println();
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
[0] 1 
[1] 1 1 
[2] 1 2 1 
[3] 1 3 3 1 
[4] 1 4 6 4 1 
[5] 1 5 10 10 5 1 
[6] 1 6 15 20 15 6 1 
[7] 1 7 21 35 35 21 7 1 
[8] 1 8 28 56 70 56 28 8 1 
[9] 1 9 36 84 126 126 84 36 9 1 
1
2
3
4
5
6
7
8
9
10

拓展题:

package arrayTest;

public class Demo6 {
    public static void main(String[] args) {
        int[] arr = new int[6];
        int count = 0;
        for (int i = 0; i < arr.length; i++) {
            while (true) {
                boolean flag = true;
                int number = (int) (Math.random() * 30 + 1);
                System.out.print("\t随机值:" + number);
                for (int j = 0; j < count; j++) {
                    if (arr[j] == number) {
                        System.out.print("\t已存在!将重新生成!");
                        flag = false;
                    }
                }
                if(flag){
                    System.out.println("\t插入成功");
                    arr[i] = number;
                    count++;
                    break;
                }
            }
        }
        System.out.print("最后生成的值如下:");
        for (int i : arr) {
            System.out.print(i + " ");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31

# 数组中涉及的常见算法

  1. 数组元素的赋值(杨辉三角、回型数等)
  2. 求数值型数组中元素的最大值、最小值、平均数、总和等。
  3. 数组的复制、反转、查找(线性查找、二分法查找等)
  4. 数组元素的排序算法

# 数值型相关练习

求数值型数组中元素的最大值、最小值、平均数、总和等。

定义一个int型的一维数组,包含10个元素,分别赋随机整数,然后求出所有元素的最大值,最小值,和值,平均值,并输出在控制台。

要求:所有随机数都是两位数。

实现代码:

package arrayTest;

/**
 * 求数值型数组中元素的最大值、最小值、平均数、总和等。
 * <p>
 * 定义一个int型的一维数组,包含10个元素,分别赋随机整数,然后求出所有元素的最大值,最小值,和值,平均值,并输出在控制台。
 * <p>
 * 要求:所有随机数都是两位数。
 */
public class Demo9 {
    public static void main(String[] args) {
        int[] arr = new int[10];
        //最大值
        int max = 0;
        //最小值
        int min = 100;
        //和值
        int total = 0;

        for (int i = 0; i < arr.length; i++) {
            arr[i] = (int) (Math.random() * 90 + 10);
            System.out.print(arr[i] + "\t");
            //最大值
            if (max < arr[i]) {
                max = arr[i];
            }
            //最小值
            if (min > arr[i]) {
                min = arr[i];
            }
            //和值
            total += arr[i];

        }
        System.out.println();
        //平均值
        double avg = (double) total / arr.length;
        System.out.println("最大值为:" + max);
        System.out.println("最小值为:" + min);
        System.out.println("和值为:" + total);
        System.out.println("平均值为" + avg);
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43

# 数组的复制

使用简单数组

  1. 创建一个名为ArrayTest的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。
  2. 使用大括号{},把array1初始化8个素数:2,3,5,7,11,13,17,19.
  3. 显示array1的内容。
  4. 赋值array2变量等于array1,修改array2中的偶索引元素,时期等于索引值(如array[0]=0,array[2]=2)。打印出array1。

思考:array1和array2是什么关系?

拓展:修改题目,实现array2对array1数组的复制。

package arrayTest;

/**
 * 使用简单数组
 * <p>
 * 1. 创建一个名为ArrayTest的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。
 * 2. 使用大括号{},把array1初始化8个素数:2,3,5,7,11,13,17,19.
 * 3. 显示array1的内容。
 * 4. 赋值array2变量等于array1,修改array2中的偶索引元素,时期等于索引值(如array[0]=0,array[2]=2)。打印出array1。
 * <p>
 * 思考:array1和array2是什么关系?
 * <p>
 * 拓展:修改题目,实现array2对array1数组的复制。
 */
public class ArrayTest {
    public static void main(String[] args) {
        int[] array1, array2;
        array1 = new int[]{2, 3, 5, 7, 11, 13, 17, 19};
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }
        array2 = array1;
        for (int i = 0; i < array2.length; i++) {
            if (i % 2 == 0) {
                array2[i] = i;
            }
        }
        System.out.println();
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33

结果:

2	3	5	7	11	13	17	19	
0	3	2	7	4	13	6	19
1
2

思考:array1和array2是什么关系?

array1和array2地址值相同,都指向了堆空间的唯一的一个数组实体。所以修改array2时,实际上是修改内存中的实际值,当修改完毕后,array1也是指向这个内存,所以它打印的值也显示更改了。

image-20201208095940116

赋值array2变量等于array1

数组不能这样赋值,如果要复制一份,需要重新在内存中开辟新的空间,重新新建数组实体。

array2 = new int[array1.length];
for (int i = 0; i < array1.length; i++) {
    array2[i] = array1[i];
}
1
2
3
4

完整代码:

package arrayTest;

/**
 * 使用简单数组
 * <p>
 * 1. 创建一个名为ArrayTest的类,在main()方法中声明array1和array2两个变量,他们是int[]类型的数组。
 * 2. 使用大括号{},把array1初始化8个素数:2,3,5,7,11,13,17,19.
 * 3. 显示array1的内容。
 * 4. 赋值array2变量等于array1,修改array2中的偶索引元素,时期等于索引值(如array[0]=0,array[2]=2)。打印出array1。
 * <p>
 * 思考:array1和array2是什么关系?
 * <p>
 * 拓展:修改题目,实现array2对array1数组的复制。
 */
public class ArrayTest {
    public static void main(String[] args) {
        int[] array1, array2;
        array1 = new int[]{2, 3, 5, 7, 11, 13, 17, 19};
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }
        /**
         * array1和array2地址值相同,都指向了堆空间的唯一的一个数组实体。
         * 所以修改array2时,实际上是修改内存中的实际值,
         * 当修改完毕后,array1也是指向这个内存,所以它打印的值也显示更改了。
         */
//        array2 = array1;
        //复制数组
        array2 = new int[array1.length];
        for (int i = 0; i < array1.length; i++) {
            array2[i] = array1[i];
        }
        //修改array2中的偶索引元素,时期等于索引值(如array[0]=0,array[2]=2)
        for (int i = 0; i < array2.length; i++) {
            if (i % 2 == 0) {
                array2[i] = i;
            }
        }
        System.out.println();
        for (int i = 0; i < array1.length; i++) {
            System.out.print(array1[i] + "\t");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44

输出结果:

2	3	5	7	11	13	17	19	
2	3	5	7	11	13	17	19	
1
2

# 数组的反转操作

方式一:

package arrayTest;

public class Demo10 {
    public static void main(String[] args) {
        String[] arr = new String[]{"JJ", "DD", "MM", "BB", "GG", "AA"};
        //数组的反转
        for (int i = 0; i < arr.length / 2; i++) {
            String temp = arr[i];
            arr[i] = arr[arr.length - i - 1];
            arr[arr.length - i - 1] = temp;
        }
        for (int i = 0; i < arr.length; i++) {
            System.out.print(arr[i] + "\t");
        }
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

方式二:

//方式二:
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
    String temp = arr[i];
    arr[i] = arr[j];
    arr[j] = temp;
}
1
2
3
4
5
6

# 数组中常见的异常

这两种异常,编译时都不会报错。

  1. 数组角标越界的异常:ArrayIndexOutOfBoundsException
  2. 空指针异常:NullPointerException

# 数组脚标越界异常(ArrayIndexOutOfBoundsException)

访问到了数组中的不存在的脚标时发生。

int[] arr= new int[2];
System.out.println(arr[2]);
System.out.println(arr[-1]);
1
2
3

# 空指针异常(NullPointerException)

arr引用没有指向实体,却在操作实体中的元素时。

int[] arr= null;
System.out.println(arr[0]);
1
2
帮我改善此页面 (opens new window)
#数组
上次更新: 2020/12/18, 12:50:58
流程控制-循环结构
排序算法

← 流程控制-循环结构 排序算法→

最近更新
01
zabbix学习笔记二
02-28
02
zabbix学习笔记一
02-10
03
Linux访问不了github
12-08
更多文章>
Theme by Vdoing | Copyright © 2020-2022 Saul.J.Wu | MIT License
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式