数组 & Arrays工具类

06.JAVASE 数组 & Arrays工具类

定义:存放相同数据类型的一组数据的容器

1.数组初始化 & 使用

1.1格式

  1. 声明:数据类型 [ ] 数组名; (eg:int[ ] a;)表示向计算机申请在内存开辟连续的int类型的空间
  2. 赋值:数据类型 [ ] 数组名 = new 数据类型 [ 数据长度 ];
  3. 使用

1.2数组的访问方式

数组名[ 下标 / 索引 / index]

索引范围:[ 0 - 数组长度 - 1 ]

1.3数组的快速初始化

  1. 静态初始化:初始化时不需要定义数组的长度,但要指定元素的值,系统根据定义的元素个数得出数组的长度

            //格式一
            数组类型[ ]数组名 = new 数组类型[ ] { 元素一,元素二 … }
    		int[] arr = new int[ ]{11, 22, 33, 44, 55};
            //一般适用于匿名对象
    
            //格式二
            数据类型[ ] 数组名 = { 元素一,元素二 … }
    		int[ ] arr = {11, 22, 33, 44, 55};
    
  2. 动态初始化:在初始化的同时确定数组大小,但不指定元素的值,后期通过动态指定,系统会根据数据类型分配相应的默认值

    		数据类型[] 数组名 = new 数据类型[数组大小]
    		double[] scores = new double[30];
    
    动态初始化给值时:需要有new:
        arr = new int[]{1,2,3.4};
    	//不能直接 arr = {1,2,3.4};
    	//以为需要在堆区开辟空间,获取地址值
    

    分配规则:

    数据类型默认值
    byte short int long0
    float double0.0
    char‘\u0000’ 就是一个空字符
    booleanfalse
    引用类型null
  3. 如何快速初始化数组?、

    1. 通过静态初始化(快速初始化,直接赋值)
    2. 通过键盘输入(生产环境)
    3. 通过随机数(测试)

2.注意事项

2.1数组的特点

  1. 数组是一个容器
  2. 数组是变量,需满足声明,再赋值
  3. 数组是引用数据类型,赋值不同于基本数据类型,不能存放数值,只能存放地址(地址值的获取必须由系统分配空间,并且随机分配地址)
  4. 数组中每一个元素的数据类型可以是八大基本数据类型,同时也可以是引用数据类型
        int i = 10;

        //int[] arr;
        //arr = 10;

        //这是错误的,引用数据类型(数组在内)不能存放数值,只能存放地址
        //而想存放地址,就必须在系统开辟空间
        //堆区:存放new出来的东西 ( eg:int[ ] arr = new int[3];  Scanner input = new Scanner(System.in);)
        //所以需要new int[数组长度]来获取地址 

2.2问题

  1. 为什么数组中每一个元素会有默认值?

    ----因为不同于栈区变量没有默认值堆区每个变量都有默认值

  2. NullPointerException是如何出现的?(空指针异常

            int[] arr = null;
            System.out.println(arr);
            //产生原因:null是默认值,对象没有分配地址,直接去访问的话,会找不到地址,即空指针异常
            //解决方法:给对象分配地址,即 new
    
  3. java.lang.ArrayIndexOutOfBoundsException(数组越界)

    ----超出了索引范围:[ 0 - 数组长度 - 1 ]

2.3垃圾回收机制

  1. System.gc();// 启动垃圾回收器
  2. System.runFinalization();// 通知垃圾回收期执行回收垃圾的方法
  3. 但是显示回收不一定起作用,因为可能正在在回收别的垃圾

3.值传递 & 引用传递

传递: 实参赋值给形参

形参可以是八大基本数据类型引用数据类型

3.1" == "比较问题

  • 基本数据类型比较时,比较的是数值
  • 引用数据类型比较时,比较的是地址值
形参传递本质
值传递八大基本数据类型传递数值本身
引用传递引用数据类型传递地址值
//值传递
public class ArrayDemo06 {
	public static void main(String[] args) {
		int a = 10;
		System.out.println("main方法中a的值: " + a);//结果是:10
		change(a);//结果是:15
		System.out.println("main方法中调用change方法后a的值: " + a)//结果是:10
	}
    
	public static void change(int a) {
		a += 5;
		System.out.println("change方法的a的值: " + a);
	}	
	//调用方法时,方法在栈区开辟了新的空间压栈,
    //和主函数的main不在用一个空间内,两个int a并不是同一个值
    //所以互不影响
//引用传递
public class ArrayDemo06 {
	public static void main(String[] args) {
		int[] arr = new int[]{ 11, 22, 33 };
		System.out.println("main方法中数组arr每一个元素的值: " + Arrays.toString(arr));//结果: [11, 22, 33]
		
		changeArr(arr);//结果:[11, 666, 33]
		System.out.println("main方法经过方法调用后中数组arr每一个元素的值: " + Arrays.toString(arr));//结果:[11, 666, 33]
		
	}
	
	public static void changeArr(int[] arr) {
		arr[1] = 666;
		System.out.println("changeArr方法中数组每一个元素的值: " + Arrays.toString(arr));
	}
}
//因为方法调用的参数arr是同一个变量,所以地址值是相同,在堆区指向的空间的相同的,对arr[1]的重新赋值,会导致元素值发生改变,所以再次打印的数组是已经改变的数组。
    //多个引用指向同一个堆区空间的问题
    public class ArrayDemo07 {
        public static void main(String[] args) {
            int[] arr = { 11, 22, 33 };
            int[] arr2 = { 44, 55, 66 };
            int[] arr3 = arr;//!!!!

            System.out.println(Arrays.toString(arr));
            System.out.println(Arrays.toString(arr2));
            System.out.println(Arrays.toString(arr3));

            arr[1] = 666;
            System.out.println(Arrays.toString(arr)); // [11, 666, 33]
            System.out.println(Arrays.toString(arr2)); // [44, 55, 66]
            System.out.println(Arrays.toString(arr3)); // [11, 666, 33]
        }
    }
    //arr3与arr地址相同,所以任何一个引用如果修改了堆区的内容,那么必然会影响到所有的引用

4.内存中的堆区

堆区的特点:

  1. 堆区每个变量都有默认值(1.3初始化分配规则)
  2. new出来的东西系统都会在堆区开辟空间,并随机赋上地址值
  3. 在堆区的对象使用完毕后,并不会马上消失,需要等待垃圾回收器空闲的时候自动回收

5.数组的功能实现

  1. 循环输出数列的值

            /*
             * 功能: 循环输出数列的值
             * 参数列表: int[] arr
             * 返回值类型: void
             * 方法名: printArray
             */
            public static void printArray(int[] arr) {
                for (int i = 0; i < arr.length; i++) {
                    System.out.println(arr[i]);
                }
            }
    
  2. 求数列中所有数值的和

            /*
             * 功能: 求数列中所有数值的和。
             * 参数列表: int[] arr
             * 返回值类型: int
             * 方法名: getSum 
             */
            public static int getSum(int[] arr) {
                int sum = 0;
                for (int i = 0; i < arr.length; i++) {
                    sum += arr[i];
                }
                return sum;
            }
    
  3. 求出最大值

            /*
             * 功能: 求出最大值。
             * 参数列表: int[] arr
             * 返回值类型: int
             * 方法名: getMaxValue
             */
            public static int getMaxValue(int[] arr) {
                // 假定第一个数为最大值
                int max = arr[0];
    
                // 遍历数组中的每一个元素
                for (int i = 0; i < arr.length; i++) {
                    // 获取到每一个元素i 
                    // 将元素和max进行比较
                    // 如果元素比假定的max还要大,那么就将该数设置为max
                    if (arr[i] > max) {
                        max = arr[i];
                    }
                }
                return max;
    		}
    
  4. 将数组倒置

            /*
             * 功能: 将数组倒置
             * 参数列表: int[] arr
             * 返回值类型: void
             * 方法名: reverseArray
             */
             public static void reverseArray(int[] arr) {
                for (int i = 0; i < arr.length / 2; i++) {
                    // arr[i]和arr[arr.length - 1 - i] 交换位置
                    int temp = arr[i];
                    arr[i] = arr[arr.length - 1 - i];
                    arr[arr.length - 1 - i] = temp;
                }
            }
    
  5. 数据查找(基本查找boolean型)

            /*
             * 功能:基本查找
             * 参数列表: int[] arr, int num
             * 返回值类型: boolean
             * 方法名: basicSearch
             */
            public static boolean basicSearch(int[] arr, int num) {
                boolean flag = false;
    
                for (int i = 0; i < arr.length; i++) {
                    if (num == arr[i]) {
                        flag = true;
                        break;
                    }
                }
                return flag;
            }
    
  6. 数据查找(基本查找int型)

            /*
             * 功能:基本查找
             * 参数列表: int[] arr, int num
             * 返回值类型: int
             * 方法名: basicSearch2
             */
            public static int basicSearch2(int[] arr, int num) {
                int index = -1;
                for (int i = 0; i < arr.length; i++) {
                    if (num == arr[i]) {
                        index = i;
                        break;
                    }
                }
                return index;
            }
    
  7. 二分法查找

        /*
         * 功能: 查找某个数在数列中的位置
         * 返回值类型: int
         * 参数列表: int[] arr, int num
         * 方法名: binarySearch
         */
        public static int binarySearch(int[] arr, int num) {
            // 1.定义最小索引和最大索引
            int min = 0;
            int max = arr.length - 1;
         
            // 2.计算中间索引
            int mid = (min + max) / 2;
         
            // 3.拿中间索引所对应的数值和需要查找的数据进行比较
            // 由于不知道比较多少次,选择while循环
            // arr[mid] != mid 就继续循环
            while (arr[mid] != num) {
                if (arr[mid] > num) {
                    // 在左边找
                    max = mid - 1;
                } else if (arr[mid] < num) {
                    // 在右边找
                    min = mid + 1;
                }
         
                // 如果最小索引超过了最大索引,说明没找到
                if (min > max) {
                    return -1;
                }
         
                // 重新计算中间索引
                mid =  (min + max) / 2;
            }
         
            // 如果中间索引所对应的数值和需要查找的数据相等,就直接返回中间索引
            return mid;
        }
    

6.八大排序

排序算法: 冒泡 选择 插入 堆 希尔 快速排序 归并排序 基数排序

  1. 冒泡排序:相邻两个元素进行比较,前面的数大于后面的数,交换两个数在这里插入图片描述

            for (int i = 0; i < arr.length - 1; i++) {
                        for (int j = 0; j < arr.length - 1 - i; j++) {
                            if (arr[j] > arr[j+1]) {
                                int temp = 0;
                                temp = arr[j];
                                arr[j] = arr[j+1];
                                arr[j+1] = temp;
                            }
                        }
                    }
                    System.out.println("冒泡排序后: " + Arrays.toString(arr));
                }
                //1.相邻两个元素进行比较,前面的数大于后面的数,交换两个数
                //2.一个比较了 arr.length - 1趟
                //3.每一趟比上一趟少比较一次
    
  2. 选择排序:从最左边开始,依次和右边所有元素比较,较小的数往前移动,每一趟比较完后,最小数出现在最前面在这里插入图片描述

            for (int i = 0; i < arr.length - 1; i++) {
                        for (int j = i+1; j < arr.length; j++) {
                            if (arr[i] > arr[j]) {
                                int temp = 0;
                                temp = arr[i];
                                arr[i] = arr[j];
                                arr[j] = temp;
                            }
                        }
                    }
                    System.out.println("选择排序后: " + Arrays.toString(arr));
                }
            //1.将指定的元素依次和后面每一个元素进行比较
            //2.一共比较了arr.length - 1趟
            //3.每一趟比
    
  3. 插入排序:从后向前,逐个比较数值大小,找到相应的位置插入(前小后大)

            for (int i = 1; i < arr.length ; i++) {
                        for (int j = 0; j < i; j++) {
                            if (arr[i] < arr[j]) {
                                int temp = 0;
                                temp = arr[i];
                                arr[i] = arr[j];
                                arr[j] = temp;
                            }
                        }
                    }
                    System.out.println("排序后: " + Arrays.toString(arr));
                }
            //1.从第一个元素开始(不是第0个)
            //2.只要前一个元素大于当前元素,该元素就向前移动
            //3.直到前一个元素等于或小于当前元素(停止之后的比较),并放置在这后面
    

6.1排序方法的效率

快速排序 > 冒泡排序 > 选择排序 > 插入排序

		// 返回1970年到当前一共经历了多少个毫秒
		long start = System.currentTimeMillis();
		// bubbleSort(arr); // 127
		// selectSort(arr); // 39
		// inertSort(arr); // 42
		quickSort(arr); // 4
		// 返回1970年到当前一共经历了多少个毫秒
		long end = System.currentTimeMillis();

7.foreach遍历数组

foreach的设计使用来简化遍历的

        //格式
        for(元素数据类型 元素名 : 数组/集合) {
            System.out.println(元素变量名)
        }

7.1普通for和foreach的区别

  • foreach更简洁
  • foreach没有索引,普通for有索引
  • foreach的底层是普通for,只不过定义了一个临时数组过渡

8.可变参数

用于多个参数数据类型一致,但数量不同的方法

特点

  1. 可变参数的本质还是数组,参数数据类型一致,数量不同
  2. 可变参数的 " … " 位置在数据类型和变量名之间(eg:int … a)
  3. 可变参数必须出现在参数列表的最后,因为要是在前面,会吸收所有的值,后面的参数无法赋值

9.Arrays工具类

针对数组操作的工具类,方便操作数组

9.1Arrays.copyOf & System.arraycopy

实现对数组的任意位置的任意元素进行增加和删除

优点:查询和修改效率非常高 【索引】

缺点:数组作为容器增加和删除的效率低(因为数组声明赋值的时候就确定了长度,所以增删实际上都是创建了新的数组)

本质:是一种(数据结构:栈 队列 堆 哈希表 链表 二叉树…)

9.2工具类的部分功能

  1. 遍历

    		// 遍历
    		String s = Arrays.toString(arr);
    		System.out.println(s);
    
  2. 快速排序

    		// 排序
    		Arrays.sort(arr);
    		System.out.println("排序后: " + Arrays.toString(arr));
    
  3. 二分法查找

    		// 二分法查找
    		System.out.println("排序后: " + Arrays.binarySearch(arr, 22));
    
  4. 数组拷贝(Arrays.copyOf)

    		// 数组的拷贝
    		// 第一个参数表示需要拷贝的源数组
    		int[] newArr = Arrays.copyOf(arr, arr.length);
    		System.out.println("拷贝后的数组: " + Arrays.toString(newArr));
    		//最末尾增加
    		int[] addArr = Arrays.copyOf(arr, arr.length + 1);
    		System.out.println("拷贝后的数组: " + Arrays.toString(addArr));
    		//在末尾减少
    		int[] removeArr = Arrays.copyOf(arr, arr.length - 1);
    		System.out.println("拷贝后的数组: " + Arrays.toString(removeArr));
    
  5. 数组拷贝(System.arraycopy)

    		/*
    		 * 数组拷贝
    		 * src: 需要拷贝的源数组
    		 * srcPos: 源数组的拷贝的起始索引
    		 * dest: 需要拷贝的目标数组
    		 * destPos: 需要拷贝的目标数组的起始索引
    		 * length: 从源数组中拷贝多少个长度到目标数组
    		 */
    		int[] srcArr = {11, 22, 33, 99, 55, 88};
    		int[] destArr = new int[srcArr.length];
    		
    		System.out.println(Arrays.toString(destArr));
    		System.arraycopy(srcArr, 0, destArr, 0, srcArr.length);
    		System.out.println(Arrays.toString(destArr));
    
  6. 填充数组

    		// 填充数组
    		Arrays.fill(arr, 1);
    		System.out.println(Arrays.toString(arr));
    

10.二维数组

存放一维数组的数组(数组可以存放引用数据类型,数组是引用数据类型)

10.1动态初始化

  •     //格式一:
        数据类型[][] 数组名 = new 数据类型[m][n];
        
        //变式:
        数据类型 数组名[][] = new 数据类型[m][n];
        数据类型[] 数组名[] = new 数据类型[m][n];
    
  •     //格式二:
        数据类型[] 数组名[] = new 数据类型[m][];
    

    注意

    • m是必不可少的,n可以省略
    • m表示的是二维数组中,一维数组的数量
    • n表示的是一维数组中,元素的数量
		//n省略的情形
		int[][] arr = new int[3][];
		
		System.out.println(arr); // [[I@7852e922
		
		System.out.println(arr[0]); // null
		System.out.println(arr[1]); // null
		System.out.println(arr[2]); // null

		System.out.println(arr[0][0]); // java.lang.NullPointerException(空指针异常)
		//一维数组没有new去开辟堆区的空间,没有地址值
		//所以是默认值:null
		//直接arr[0][0]会出现空指针异常的报错
		//需要对每一个一维数组进行new

		//解决方式:
		arr[0] = new int[3];
		arr[1] = new int[1];
		arr[2] = new int[] {11,22,33,44};

		System.out.println(arr[0]); // [I@4e25154f
		System.out.println(arr[1]); // [I@70dea4e
		System.out.println(arr[2]); // [I@5c647e05

		System.out.println(arr[0][0]); // 0
		System.out.println(arr[0][1]); // 0

10.2静态初始化

//格式一:
数据类型[][] 数组名 = {{元素1,元素2}, {元素3,元素4,元素5}, {元素6}};
//格式二:
数据类型[][] 数组名 = new 数据类型[][]{{元素1,元素2}, {元素3,元素4,元素5}, {元素6}};

10.3二维数组的遍历

二维数组是不能通过Arrays.toString(数组名)来实现遍历的

		//Arrays.toString(arr)遍历的是一维数组的地址值
		int[][] arr = new int[][]{{11,22,33},{44,55,66,77},{33,22}};
		System.out.println(Arrays.toString(arr));

		//[[I@15db9742, [I@6d06d69c, [I@7852e922]
       	 //二维数组的遍历方法
        for (int i = 0; i < arr.length; i++) {
             for (int j = 0; j < arr[i].length; j++) {
                 System.out.println(arr[i][j]);
             }
        }

10.4一二维数组地址的区别

  • 一维数组:[I@+(Number…) ( eg: [I@7852e922
  • 二维数组:[[I@+(Number…) ( eg: [[I@7852e922

*10.5二维数组的面试题

    int[] x,y[];  
    //int[] x ;int[]y[];


    int n[] = new int[2],i,j,k;
    //int n[] = new int[2];
    //int i;
    //int j;
    //int k;

//“,”表示的是分别声明赋值 (eg:for(int i = 0,y = 0; ; ) { } 
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值