当前位置:   article > 正文

JavaSE-06笔记【数组(+2024新)】

JavaSE-06笔记【数组(+2024新)】


突然在B站发现动力节点出了2024版JavaSE的视频(本部分的见 Java零基础视频教程 _中部),扩充了好多内容啊,在后面的内容边学边结合起来,补充上来吧!(仅补充部分个人觉得需要的)。

1. 数组概要

  1. 什么是数组?
  • 在Java中,数组是一种用于存储多个相同数据类型元素的容器。
  • 例如一个存储整数的数组:int[] nums = {100, 200, 300};
  • 例如一个存储字符串的数组:String[] names = {“jack”,“lucy”,“lisi”};
  • 数组是一种引用数据类型,隐式继承Object。因此数组也可以调用Object类中的方法。
  • 数组对象存储在堆内存中,在内存中存储示意图如下:
    在这里插入图片描述
  1. 数组的分类?
  • 根据维数进行分类:一维数组,二维数组,三维数组,多维数组。
  • 根据数组中存储的元素类型分类:基本类型数组,引用类型数组。
  • 根据数组初始化方式不同分类:静态数组,动态数组。
  1. Java数组存储元素的特点?
  • 数组长度一旦确定不可变。
  • 数组中元素数据类型一致,每个元素占用空间大小相同。
  • 数组中每个元素在空间存储上,内存地址是连续的,以首元素的内存地址作为数组对象在堆内存中的地址。
  • 数组元素是有下标的,下标从 0 开始,也就是第一个元素的下标为 0,依次类推最后一个元素的下标为 n-1,我们可以通过数组的下标来访问数组的元素;
  • 数组作为对象,数组中的元素作为对象的属性,除此之外数组还包括一个成员属性 length,length 表示数组的长度;

2. 一维数组的声明和使用

2.1 数组的声明

一维数组是线性结构。二维数组,三维数组,多维数组是非线性结构。
一维数组的声明格式有以下两种:

  1. 数组元素的类型[] 变量名称(变量名称即引用,保存的是数组的地址)
  2. 数组元素的类型 变量名称[]

数组元素的类型,可以是 java 中的任意类型,变量名称可以是任意合法的标识符,上面两种
格式较常用的是第一种,例如:
int [] a;
Student[] stu;
在一行中也可以声明多个数组,例如:int[] a, b, c

2.2 数组的创建

数组有两种创建方式

2.2.1 动态初始化

使用 new 操作符来创建数组,格式为:new 数组元素的数据类型[数组元素的个数]动态初始化数组时,会给数组中的元素赋该类型的默认值!!!

  1. 基本类型的数组
package arraytest;

public class ArrayTest01 {
    public static void main(String[] args) {
        //声明 int 类型的数组,长度为 5
        //数组中的元素必须为 int 类型
        int[] data = new int[5];
        //对数组中的元素进行赋值,如果不赋值默认为该类型的默认值,以上数组默认为 0
        //如何赋值?变量名[下标],下标从 0 开始
        data[0] = 1;
        data[1] = 2;
        data[2] = 3;
        data[3] = 4;
        data[4] = 5;
        //输出数组中的元素,变量名[下标]
        System.out.println(data[0]);
        System.out.println(data[1]);
        System.out.println(data[2]);
        System.out.println(data[3]);
        System.out.println(data[4]);
        System.out.println("-----------------------");
        //采用 length 属性可以取得数组的长度
        for (int i=0; i<data.length; i++) {
            System.out.println(data[i]);
        }
        //输出指定的数组元素
        System.out.println("data[3]=" + data[3]);
        //数组下标越界
        //会抛出 ArrayIndexOutOfBoundsException 异常
        System.out.println("data[10]=" + data[10]);
        //不能成功赋值,数组中的类型必须是一种类型
        //data[0] = "iiii";
    }
}
  • 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

内存结构变化:
在这里插入图片描述
在这里插入图片描述
必须清楚数组为引用类型,它在堆中分配。

  1. 引用类型的数组
package arraytest;

public class ArrayTest02 {
    public static void main(String[] args) {
        //声明引用类型的数组
        Student[] students  = new Student[2];

        students[0].id = 1;
        students[0].name = "Susan";

        students[1].id = 2;
        students[1].name = "Jack";


    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
public class Student{
    int id;
    String name;
}
  • 1
  • 2
  • 3
  • 4

出现空指针异常:
在这里插入图片描述

对于引用类型的数组,一定要注意,new完数组并没有new完其中的对象,其中的对象在内存中还是默认值null,所以一定要再把对象new出来!

  • 修改:
package arraytest;

public class ArrayTest03 {
    public static void main(String[] args) {
        //声明引用类型的数组
        Student[] student  = new Student[2];
//        //方式一:
//        student[0] = new Student();
//        student[0].id = 1;
//        student[0].name = "Susan";
//
//        student[1] = new Student();
//        student[1].id = 2;
//        student[1].name = "Jack";
        //方式二:
        Student stu1 = new Student();
        stu1.id = 1;
        stu1.name = "Susan";
        student[0] = stu1;

        Student stu2 = new Student();
        stu2.id = 2;
        stu2.name = "Jack";
        student[1] = stu2;

        for (int i=0; i<student.length; i++) {
            System.out.println("id=" + student[i].id + ", name=" + student[i].name);
        }
    }
}
  • 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

运行结果:
在这里插入图片描述
内存结构变化图:
在这里插入图片描述
在这里插入图片描述

2.2.2 静态初始化

使用数组的初始化语句,格式有两种:

  • 第一种: 数组元素的类型[] 变量名称 = {数组元素1, 数组元素2,...,数组元素n}数组元素的类型 变量名称[] = {数组元素1, 数组元素2, ...,数组元素n};
  • 第二种:数组元素的类型[] 变量名称 =new 数组元素的类型[]{数组元素1, 数组元素2,...,数组元素n}
package arraytest;

public class ArrayTest04 {
    public static void main(String[] args) {
        //静态初始化
        int[] data = {1,2,3,4,5};

        for (int i = 0; i < data.length; i++) {
            System.out.println(data[i]);
        }

        Student stu1 = new Student();
        stu1.id = 1;
        stu1.name = "Susan";

        Student stu2 = new Student();
        stu2.id = 2;
        stu2.name = "Jack";

        //静态初始化
        Student[] students = {stu1, stu2};
        for (int i=0; i<students.length; i++) {
            System.out.println("id=" + students[i].id + ", name=" +
                    students[i].name);
        }
    }
}
  • 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

运行结果:
在这里插入图片描述

一个错误写法:

package arraytest;

public class ArrayTest05 {
    public static void main(String[] args) {
        int[] a = {1,2,3};
        printArray(a);
        System.out.println("===============");
        //没有这种语法
//        printArray({1,2,3});
        //直接传递一个静态数组的话,语法必须这样写
        printArray(new int[]{1,2,3});
    }

    private static void printArray(int[] a) {
        for (int i = 0; i < a.length; i++) {
            System.out.println(a[i]);
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

编译报错:
在这里插入图片描述
注释后再运行:
在这里插入图片描述

2.2.3 两种创建方式的共同点以及main中的String[] args

String[] strs= new String[0]String strs={} //均表示数组对象创建了,但是数组中没有任何数据。
对于main方法中所传的String[] args数组,主要是用来接收用户输入参数的,长度默认为0,在运行时,若使用:java 类名 abc sde 就是相当于传了两个元素进该数组。(了解即可)

2.2.4 两种创建方式如何选择

当创建数组时,确定数组中所需存储的元素,采用静态初始化;
否则采用动态初始化,预先分配内存。

2.3 一维数组的扩容

数组的长度一旦确定不可变,若需扩容需要先新创建一个大容量的数组,然后将后将小容量数组中的数据一个个拷贝到大数组中去。
结论: 数组扩容由于涉及拷贝问题,所以其扩容效率较低,应尽量避免进行数组扩容,在创建时预估好其长度。
数组拷贝函数:
System.arraycopy(源数组名称,拷贝起始位置,目标数组名称,存放起始位置,拷贝长度);
对于引用数据类型,其拷贝的其实也就是对象的地址。

3. 二维数组的声明和使用

二维数组属于多维数组。多维数组即数组元素的类型也是数组,可以这么理解:二维数组其实就是一个特殊的一维数组,该一维数组中每一个元素都是一个一维数组「每个一维数组长度不定」。
而三维数组就是一个特殊的二维数组,其中每一个元素都是一个一维数组。[三维数组几乎不用]

3.1 二维数组的声明

格式如下:

  1. 数组元素的数据类型[][] 变量名;
  2. 数组元素的数据类型 变量名[][];
    其中方括号的个数就是数组的维数,声明二维数组如下:int [][] data;

3.2 二维数组的创建

3.2.1 动态初始化(等长)

package arraytest;

public class ArrayTest06 {
    public static void main(String[] args) {
        // 声明二维数组
        int[][] data = new int[2][3]; //两行三列,两个一维数组,每个一维数组中3个元素

        // 对二维数组赋值
        data[0][0] = 1;
        data[0][1] = 2;
        data[0][2] = 3;
        data[1][0] = 4;
        data[1][1] = 5;
        data[1][2] = 6;

        //输出二维数组
        //data.length是其所含一维数组的个数
        //data[i].length是对应一维数组i中元素的个数
        for (int i = 0; i < data.length; i++) {
            for (int j = 0; j < data[i].length; j++) {
                System.out.println(data[i][j]);
            }
        }
    }
}
  • 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

运行结果:
在这里插入图片描述
内存结构变化图:
在这里插入图片描述
在这里插入图片描述

3.2.2 动态初始化(不等长)

package arraytest;

public class ArrayTest07 {
    public static void main(String[] args) {
        //从高维开始逐维创建
        int[][] data = new int[2][];
        data[0] = new int[2];
        data[1] = new int[4];
        data[0][0] = 1;
        data[0][1] = 2;
        data[1][0] = 1;
        data[1][1] = 2;
        data[1][2] = 3;
        data[1][3] = 4;

        //输出二维数组
        for (int i=0; i<data.length; i++) {
            for (int j=0; j<data[i].length; j++) {
                System.out.println(data[i][j]);
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

运行结果:
在这里插入图片描述

3.2.3 静态初始化

package arraytest;

public class ArrayTest08 {
    public static void main(String[] args) {
        //静态初始化,多个数组之间用逗号隔开
        int[][] data = {{1,2},{3,4,5}}; //也可以使用int[][] data =new int[][]{{1,2},{3,4,5}};
        for (int i=0; i<data.length; i++) {
            for (int j=0; j<data[i].length; j++) {
                System.out.println(data[i][j]);
            }
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

在这里插入图片描述

4. 数组的排序

4.1 冒泡排序

假设有 5 个数字 3,1,6,2,5 在一个 int 数组中,要求按从小到大排序输出,如何采用冒泡排序算法呢?
冒泡排序的算法是这样的,首先从数组的最左边开始,取出第 0 号位置(左边)的数据和第1号位置(右边)的数据,如果左边的数据大于右边的数据,则进行交换,否而不进行交换。接下来右移一个位置,取出第 1 个位置的数据和第 2 个位置的数据,进行比较,如果左边的数据大于右边的数据,则进行交换,否而不进行交换。沿着这个算法一直排序下去,最大的数就会冒出水面,这就是冒泡排序。
以上示例排序过程如下:
在这里插入图片描述
从上面我们看到了比较了 N-1 次,那么第二遍就为 N-2 次比较了,如此类推,比较次数的公式如下:(N-1) + (N-2)+…+1=((N-1)*N)/2,所以以上总共比较次数为((5-1)*5)/2=10。时间复杂度为: O ( n 2 ) O(n^2) O(n2)
具体代码如下:

package arraytest;

public class ArraySortTest01 {
    public static void main(String[] args) {
        int[] data = {3,1,6,2,5};

        // data.length - 1是因为最后一轮不需要排序
        for (int i = 0; i < data.length - 1; i++) {
            // data.length -1 - i 是因为每一轮都能确定排序好一个数(最大的数最先确定其顺序)
            for (int j = 0; j < data.length -1 - i; j++) {
                if(data[j]>data[j+1]){
                    int temp = data[j];
                    data[j] = data[j+1];
                    data[j+1] = temp;

                }
            }
        }
        for (int j = 0; j < data.length; j++) {
            System.out.print(data[j] + " ");
        }
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23

运行结果:
在这里插入图片描述

4.1.1 冒泡排序算法的优化

因为冒泡排序存在提前排序成功的可能,因此可以对以上冒泡排序算法进行优化,此处的优化思路使用了“假设法”来实现,若当前一轮的比较不存在任何元素的交换,则说明已有序,跳出排序循环。
如下代码:

package arraytest;

public class ArraySortTest01 {
    public static void main(String[] args) {
        int[] data = {3,1,6,2,5};
        
        // data.length - 1是因为最后一轮不需要排序
        for (int i = 0; i < data.length - 1; i++) {
            boolean flag = true;
            // data.length -1 - i 是因为每一轮都能确定排序好一个数(最大的数最先确定其顺序)
            for (int j = 0; j < data.length -1 - i; j++) {
                if(data[j]>data[j+1]){
                    int temp = data[j];
                    data[j] = data[j+1];
                    data[j+1] = temp;
                    //当前比较存在交换,flag置为false
                    flag = false;
                }
            }
            //当前一整轮比较都不存在交换,说明数组已经有序,提前退出
            if(false){
               break; 
            }
        }
        for (int j = 0; j < data.length; j++) {
            System.out.print(data[j] + " ");
        }
    }
}
  • 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

4.2 选择排序

选择排序对冒泡排序进行了改进,使交换次数减少(交换更有意义),但比较次数仍然没有减少。
假设有 5 个数字 3,1,6,2,5 在一个 int 数组中,要求按从小到大排序输出,采用选择排序,选择排序是这样的,先从左端开始,找到下标为 0 的元素,然后和后面的元素依次比较,如果找到了比下标 0 小的元素,那么再使用此元素,再接着依次比较,直到比较完成所有的元素,最后把最小的和第 0 个位置交换,就为最小的数找到了位置,第一遍排序结束。接着第二遍开始从下标1的元素和户名的元素开始比较,以此类推,直到数组有序。
以上示例排序过程如下:
在这里插入图片描述
第二遍排序将从下标为 1 的元素开始,以此类推,经过 N(N-1)/2 次比较(时间复杂度仍为 O ( n 2 ) O(n^2) O(n2)),经过 N 次数据交互就完成了所有元素的排序。
具体代码如下:

package arraytest;

public class ArraySortTest02 {
    public static void main(String[] args) {
        int[] data = {3,1,6,2,5};
        // data.length - 1是因为最后一轮不需要排序
        for (int i = 0; i < data.length - 1; i++) {
            // min = i 是因为每一轮都能确定排序好一个数(最小的数最先确定其顺序)
            int min = i;
            for (int j = i+1; j <  data.length ; j++) {
                //保存当前比较的小数的下标
                if(data[min]>data[j]){
                    min = j;
                }
            }
            //进行位置交换
            if(min != i){ //先判断一下,保证交换有效
                int temp = data[min];
                data[min] = data[i];
                data[i] = temp;
            }
        }

        for (int i = 0; i < data.length; i++) {
            System.out.print(data[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

运行结果:
在这里插入图片描述

5. 数组的查找

5.1 线性查找

采用逐一比对的方式进行数组的遍历,如果发现了匹配值,返回数组下标即可,这种方式称为线性查找,是一种最简单粗暴的查找法。
优点: 查找数组无需有序;
缺点: 查找的次数多,效率低下,【比较适合小型数组,大型数组效率太低】。

5.2 二分法(折半法)查找

如果一个数组已经排好序,那么我们可以采用效率比较高的二分查找(折半查找)算法。

  1. 示例如下:
    在这里插入图片描述
    假设,我们准备采用二分法取得 18 在数组中的位置
  • 首先,取得数组下标 0~9 的中间元素
    中间元素的位置为:(开始下标 0 + 结束下标 9)/2=下标 4
    通过下标 4 取得对应的值 15,18 大于 15,那么我们在后半部分查找;
  • 然后,取数组下标 5~9 的中间元素
    4~9 的中间元素 =(下标 5 +下标 9)/2=下标 7
    下标 7 的值为 18,查找完毕,将下标 7 返回即可。

以上就是二分或折半查找法,注意:二分或折半查找法必须保证数组事先是排好序的

  1. 思路总结:

假设查找的数组为升序排序,则首先定义两个变量,分别用于保存查找元素(value)所在范围的最小索引值(min)和最大索引值(max)。
然后开启二分查找,每次查找前都定义一个mid变量,并设置该变量的初始值为:(max + min)/2。在查找的过程中,发生以下三种情况,则做对应的处理。
1)如果arr[mid]大于value,则证明查找的元素在mid的左侧,那么更新max的值为:mid-1;
2)如果arr[mid]小于value,则证明查找的元素在mid的右侧,那么更新min的值为:mid+1;
3)如果arr[mid]等于value,则证明查找元素的索引值就是mid,返回mid的值即可!
在以上的操作中,我们不停的更改min和max的值,如果发生min大于max的情况,则证明查找的元素不存在,那么返回-1(表示找不到)即可!

  • 具体代码如下:
package arraytest;


public class BinarySearchTest01 {
    public static void main(String[] args) {
        int[] data = {11,12,13,14,15,16,17,18,19,20};
        int index = binarySearch(data, 18);
        System.out.println("18的下标为:" + index);
    }

    public static int binarySearch(int[] data, int value){
        // 开始下标
        int low = 0;
        // 结束下标
        int high = data.length - 1;

        while (low <= high) { //循环条件:开始元素的下标<=结束元素的下标
            int mid = (low + high) >> 1;  // 相当于(low + high)/2 , 写法要注意,不是(low + high) >> 2!!!
            if (data[mid] > value) {
                //目标值在数组前半部分
                high = mid - 1;
            } else if (data[mid] < value) {
                //目标值在数组后半部分
                low = mid + 1;
            } else if (data[mid] == value) {
                return mid; //找到目标下标,直接返回
            }
        }
        //没有找到对应元素,返回-1
        return -1;
    }
}
  • 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

在这里插入图片描述
再找下11的下标,结果:
在这里插入图片描述

  • 二分查找的优缺点
    优点: 比较次数少,查找速度快,平均性能好;
    缺点: 要求待查数组必须排序,且执行插入和删除操作困难。

6. Arrays 工具类

实际开发中,不用自己写排序、查找等算法,直接用工具类即可

6.1 Arrays.sort()方法

基于快速排序算法,适合小规模数据量排序。

6.1.1 对基本数据类型数组进行排序(直接调用)

package arraytest;

import java.util.Arrays; //已写好的工具包

public class ArraysUtilTest01 {
    public static void main(String[] args) {
        int[] data = {3,1,6,2,5};
        Arrays.sort(data); //排序方法,默认升序排序
        for (int i = 0; i < data.length ; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.println("\n----------------------------");
        for (int i = data.length - 1 ; i >= 0; i--) {
            System.out.print(data[i] + " ");
        }
        System.out.println("\n----------------------------");
    }
}

  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

运行结果:
在这里插入图片描述

6.1.2 对自定义引用数据类型数组进行排序

如下代码:

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest02 {
    //对自定义的引用类型的数组进行排序,不能直接调用Arrays.sort
    public static void main(String[] args) {
        Student student1 = new Student(1,"wang");
        Student student2 = new Student(2,"liu");
        Student student3 = new Student(3,"zhang");
        Student student4 = new Student(4,"xie");
        Student[] students = new Student[]{student1,student2,student3,student4};
        Arrays.sort(students);
        System.out.println(Arrays.toString(students)); //需要重写Student的toString方法

    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
package arraytest;

public class Student {
    int id;
    String name;

    public Student() {
    }
    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

报错(出现类型转换异常):
在这里插入图片描述
因为此时Student类还不是可比较的,需要继承Comparable类,重写其中的compareTo()方法,如下:

package arraytest;

public class Student implements Comparable{
    int id;
    String name;

    public Student() {
    }

    public Student(int id, String name) {
        this.id = id;
        this.name = name;
    }



    //compareTo方法中写自定义的比较规则,前大后小返回1,前小后大返回-1,相等返回0,
    // 定义完后Student就是可比较的了,具体比较时不需要手动调用本方法,由JDK自动调用。
    @Override
    public int compareTo(Object o) {
        Student s = (Student) o;
//        return this.name.compareTo(s.name); //按名字进行比较,即字典顺序,调用String类覆写的compareTo方法
        return this.id-s.id;
    }

    @Override
    public String toString() {
        return "Student{" +
                "id=" + id +
                ", name='" + name + '\'' +
                '}';
    }
}
  • 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

id进行比较:
在这里插入图片描述

name进行比较:
在这里插入图片描述

6.1.3 对String数组进行排序

由上1.6.1.2中按name进行排序可以看出,String类已有覆写compareTo()方法,所以其也是可比较的,可以直接调用Arrays.sort()方法对其按字典顺序排序。

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest03 {
    public static void main(String[] args) {
        String[] strings = {"a","d","b","c"};
        Arrays.sort(strings);
        System.out.println(Arrays.toString(strings));
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11

运行结果:
在这里插入图片描述

6.2 Arrays.parallelSort()方法

Arrays.parallelSort(int[] arr)方法:Java 8引入的方法,基于分治的归并排序算法,支持多核CPU排序(需要确保所用电脑是支持多核的),适合大数据量排序,效率较高。如果数据量太小的话,不要调用这个方法,因为启动多核也是需要耗费资源的。

如下代码(我的电脑好像不支持多核,结果就不放了):


package arraytest;

import java.util.Arrays;
import java.util.Random;

public class ArraysUtilTest04 {
    public static void main(String[] args) {
        //创建数组模拟大数据
        int[] arr = new int[100000000];
        Random random = new Random();
        for (int i = 0; i < arr.length; i++) {
            arr[i] = random.nextInt(100000000);
        }
        //System.currentTimeMillis()获取当前时间毫秒数(1970-1-1 0:0:0 000到当前系统时间的总毫秒数,1秒=1000毫秒)
        long begin = System.currentTimeMillis();

        //排序
        Arrays.parallelSort(arr);

        long end = System.currentTimeMillis();

        //统计排序耗时
        System.out.println(end-begin);

        long begin1 = System.currentTimeMillis();

        Arrays.sort(arr);

        long end1 = System.currentTimeMillis();

        System.out.println(end1-begin1);
    }
}
  • 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

6.3 Arrays.binarySearch()方法

注意:只能对有序数组使用。

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest05 {
    public static void main(String[] args) {
        int[] data = {3,1,6,2,5};
        Arrays.sort(data); //先排序,有序后再二分查找!
        System.out.println("排序后:");
        for (int i = 0; i < data.length ; i++) {
            System.out.print(data[i] + " ");
        }
        System.out.println();
        int index = Arrays.binarySearch(data,2); //二分查找算法,有目标元素的话,会返回元素下标,否则返回-1
        System.out.println("2的下标为:" + index);
        int index2 = Arrays.binarySearch(data, 0);
        System.out.println("0的下标为:" + index2);

    }
}


  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22

运行结果:
在这里插入图片描述

6.4 Arrays.toString()和Arrays.deepToString()方法

Arrays.toString()方法:将一维数组转换成字符串
Arrays.deepToString()方法:将多维数组转换成字符串


package arraytest;

import java.util.Arrays;

public class ArraysUtilTest06 {
    public static void main(String[] args) {
        toStringTest();
        deepToStringTest();
    }

    /**
     * Arrays.toString():将一维数组转换为字符串
     */
    public static void toStringTest(){
        int[] arr = {1,2,3,4,5};
        System.out.println(arr); //[I@1b6d3586
        System.out.println(Arrays.toString(arr)); //[1, 2, 3, 4, 5]

        String[] name = {"lili","Mary","Lucy"};
        System.out.println(name);//[Ljava.lang.String;@4554617c
        System.out.println(Arrays.toString(name)); //[lili, Mary, Lucy]
    }

    /**
     * Arrays.deepToString():将多维数组转换为字符串
     */
    public static void deepToStringTest(){
        int[][] arr2 ={{6,7,8},{9,10,11}};
        System.out.println(arr2);//[[I@74a14482
        System.out.println(Arrays.toString(arr2)); //[[I@1540e19d, [I@677327b6], 只能解析一维
        System.out.println(Arrays.deepToString(arr2));//[[6, 7, 8], [9, 10, 11]]
    }
}
  • 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

Arrays.sort()方法类似,如果要对自定义引用数据类型的数组使用Arrays.toString()方法,可以对其覆写toString()方法,否则输出的是一堆“地址”。

6.5 Arrays.equals()和Arrays.deepEquals()方法

Arrays.equals(int[] arr1, int[] arr2)方法:判断两个数组是否相等
Arrays.deepEquals(Object[] arr1, Object[] arr2)方法:判断两个多维数组是否相等

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest07 {
    public static void main(String[] args) {
        equalsTest();
        deepEqualsTest();
    }
    /**
     * Arrays.equals():判断两个一维数组内容是否相等
     */
    public static void equalsTest(){
        int[] arr1 = {1,2,3};
        int[] arr2 = {1,2,3};
        System.out.println(Arrays.equals(arr1, arr2));//true

        String[] name1 = new String[]{"lili","Mary","Lucy"};
        String[] name2 = new String[]{"lili","Mary","Lucy"};
        System.out.println(Arrays.equals(name1, name2));//true

    }

    /**
     * Arrays.deepEquals():判断两个多维数组内容是否相等
     */
    public static void deepEqualsTest(){
        int[][] arr1 = {{1,2,3},{4,5,6}};
        int[][] arr2 = {{1,2,3},{4,5,6}};
        System.out.println(Arrays.deepEquals(arr1, arr2));//true
    }
}
  • 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

6.5.1 对自定义的引用数据类型数组进行判等

也可以直接调用Arrays.equals()方法:

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest08 {
    public static void main(String[] args) {
        Person person1 = new Person(1,"wang");
        Person person2 = new Person(2,"liu");
        Person person3 = new Person(3,"zhang");
        Person person4 = new Person(4,"xie");
        Person[] persons1 = new Person[]{person1,person2,person3,person4};
        Person[] persons2 = new Person[]{person1,person2,person3,person4};
        System.out.println(Arrays.equals(persons1,persons2)); //true
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
package arraytest;
public class Person {
    int age;
    String name;

    public Person() {
    }

    public Person(int age, String name) {
        this.age = age;
        this.name = name;
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

6.6 Arrays.fill()方法

Arrays.fill(int[] arr, int data)方法:填充数组
Arrays.fill(int[] a, int fromIndex, int toIndex, int val)方法
如下代码:

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest09 {
    public static void main(String[] args) {
        int[] arr = new int[5]; //5个0

        Arrays.fill(arr, 10); //对数组填充10
        System.out.println(Arrays.toString(arr));//[10, 10, 10, 10, 10]

        Arrays.fill(arr,1, 3, 5); //对数组指定范围(下标1-2,不包括3)填充5
        System.out.println(Arrays.toString(arr));//[10, 5, 5, 10, 10]
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

6.7 Arrays.copyOf()和Arrays.copyOfRange()方法

int[] Arrays.copyOf(int[] original, int newLength)方法:数组拷贝
int[] Arrays.copyOfRange(int[] original, int from, int to)

package arraytest;

import java.util.Arrays;

public class ArraysUtilTest10 {
    public static void main(String[] args) {
        int[] arr = {1,2,3,4,5,6,7,8};

        //数组拷贝,拷贝3个长度
        int[] newArr = Arrays.copyOf(arr, 3);
        System.out.println(Arrays.toString(newArr));//[1, 2, 3]

        //数组拷贝,拷贝从下标3-5的数据,不包括下标6
        int[] newArr2 = Arrays.copyOfRange(arr, 3, 6);
        System.out.println(Arrays.toString(newArr2));//[4, 5, 6]
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17

6.8 Arrays.asList()方法

Arrays.asList(T… data)方法:将一组数据转换成List集合(T… data是一个可变长度参数)

package arraytest;

import java.util.Arrays;
import java.util.List;

public class ArraysUtilTest11 {
    public static void main(String[] args) {

        //将一串数据转换为List集合
        List<Integer> list = Arrays.asList(1, 34, 54, 56, 76, 4, 67, 2);
        for (int i = 0; i < list.size(); i++) {
            System.out.print(list.get(i) + " ");
        }
        System.out.println();
    }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16

7. 数组的优缺点

  • 优点: 查询/查找/检索某个下标上的元素时效率极高。可以说是查询效率最高的一种数据结构。理由如下:
    1)每个元素的内存地址在空间上是连续的。
    2)每个元素类型相同,占用的空间大小一样。
    3)知道第一个元素的内存地址,知道每一个元素占用空间的大小,又知道下标,所以通过一个数学表达式就可以计算出某个下标上元素的内存地址。可以直接通过内存地址定位元素,所以数组的查询效率是最高的。
    数组中存储100个元素,或者存储100万个元素,其在元素查询/检索方面效率是相同的,因为数组中元素查找的时候不会一个一个找,而是通过数学表达式计算出来的,算出一个内存地址,直接定位即可。
  • 缺点:
    1)由于为了保证数组中每个元素的内存地址连续,所以在数组上随机删除或者增加元素的时候,效率较低,因为随机增删元素会涉及到后面的元素统一向前或向后位移的操作。
    2)数组不能存储大数据量,因为很难在内存空间上找到一块特别大的连续的内存空间。

注意:对于数组中最后一个元素的增删,是不会有效率影响的。

8.一个小问题

在这里插入图片描述
在Java中,一旦你初始化了一个数组,就不能再用这种方式再次为同一个数组重新初始化。也就是说,一旦你声明并初始化了一个数组,它的大小和内容就固定了,不能再用另一个数组的内容或大小再次初始化它。

如果你想改变数组的内容,可以通过如下方法:

  1. 遍历数组的方式修改元素的值:
int[] d = {1,2,3};      
for (int i=0; i<d.length; i++) {
	d[i] += 3;
}
  • 1
  • 2
  • 3
  • 4
  1. 创建新的数组,将新数组赋给原来的数组:
int[] d = {1,2,3};
int[] d2 = {4,5,6};
d = d2;//现在d指向了新的数组{4, 5, 6},原来的数组会被垃圾回收
  • 1
  • 2
  • 3
声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/小小林熬夜学编程/article/detail/412466
推荐阅读
相关标签
  

闽ICP备14008679号