写点什么

批量处理数据神器——Java 数组与引用

作者:未见花闻
  • 2022 年 7 月 10 日
  • 本文字数:6382 字

    阅读完需:约 21 分钟

🎨1.Java 数组的基本用法

🎳1.1 数组的定义方式

🍁方式 1:




🍁方式 2:




❗️new后面那个中括号里面不能指定元素个数,必须是空的!


🍁方式 3:


🎳1.2 数组的创建与使用

🍁数组的创建:


int[] data1 = {1,2,3,4,5,6,7,8,9,0};int[] data2 = new int[]{1,2,3,4,5,6,7,8,9,0};int[] data3 = new int[10];
复制代码


🍁数组的使用:


import java.util.Arrays;
public class TestBlog { public static void main(String[] args) { //创建数组 int[] arr = new int[]{1,2,3,4,5,6,7,8,9,0}; //访问数组长度 System.out.println(arr.length); //访问数组元素 System.out.println(arr[0]); System.out.println(arr[1]); System.out.println(arr[2]); //遍历数组 1.for循环 2.foreach循环 3.toString函数
//方式1:for循环 for (int i = 0; i < arr.length; i++) { System.out.print(arr[i] + " "); } System.out.println(); //方式2:foreach循环 for (int a: arr) { System.out.print(a + " "); } System.out.println(); //方式3:toString函数 System.out.println(Arrays.toString(arr)); }}
复制代码


对于数组遍历方式 2:


for (接受变量: 数组) {  //语句块;  //此方法不能获取下标}
复制代码


对于遍历方式 3:toString是 JavaArrays类中的一个方法,能够将数组转换成字符串,有,隔开元素,中括号[]包裹数组所有元素!


🎨2.Java 类型之引用

🎳2.1 引用类型

在 Java 当中数组其实是一个对象,我们知道在数组定义时有两种方式都用到了关键字new,这个关键字就是实现类的实例化,实例出一个对象,使用一个能接收“实例化对象的值”的类型就是引用类型。这个“实例化对象的值”其实是一个地址,该地址指向该数组(对象),比如下面定义的x变量定义一个数组,这个x就是引用变量。这个与 C 语言中的指针有一点相似,但是它并不是指针,引用变量是一个值,在这里,该值是这个数组的地址。我们知道我们所定义的x变量是局部变量所以它在栈上生成,而这个数组(对象)是在堆上开辟内存的。null表示空引用,与 C 语言中的NULL很相似,表示一个无效的内存位置,既然这个内存是无效的,那肯定就不能对这个内存指向的空间进行读写。注意: Java 中并没有约定 null 0 号地址的内存有任何关联.


数据类型[] 变量名 = new int[元素个数]; (数组全部元素会初始化为0)int[] x = new int[3];x[0] = 10;x[1] = 20;x[2] = 30;
复制代码



所谓的 "引用" 本质上只是存了一个地址. Java 将数组设定成引用类型, 这样的话后续进行数组参数传参, 其实只是将数组的地址传入到函数形参中. 这样可以避免对整个数组的拷贝(数组可能比较长, 那么拷贝开销就会很大)下面用一个数组传参的例子来进一步理解引用。

🎳2.2 数组传参

public class TestBolg {    public static void arrFunc(int[] arr) {        if (arr == null) {            return;        }        for (int i = 0; i < arr.length; i++) {            arr[i] = 10 * (i+1);        }    }    public static void main(String[] args) {        int[] x = new int[3];        arrFunc(x);        System.out.println(Arrays.toString(x));    }}
复制代码





对于数组的传参就是将一引用变量的值传递给方法的形参,由于引用变量存的是对象的地址,所以方法会根据传入的参数对数组(实例化的对象)进行修改或读写操作,从而使数组内元素的值发生改变,这就是引用传递。

🎳2.3 认识 JVM 区域划分


🎨3.Java 数组应用

🎳3.1 利用数组求平均值与交换两个数

public class AvgSwap {    public static void swap(int[] data) {        int tmp = data[0];        data[0] = data[1];        data[1] = tmp;    }    public static double avg(int[] data) {        int sum = 0;        for (int i = 0; i < data.length; i++) {            sum += data[i];        }        return 1.0 * sum / data.length;    }
public static void main(String[] args) { int[] swap = {22, 33}; int[] avg = {1,2,3,4,5,6,7,8,9,0}; System.out.println("数据交换前:a = " + swap[0] + ", b = " + swap[1]); swap(swap); System.out.println("数据交换后:a = " + swap[0] + ", b = " + swap[1]); System.out.println("数组平均值为:" + avg(avg)); }}
复制代码


🎳3.2 拷贝数组

import java.util.Arrays;
public class Copy { public static int[] copy(int[] arr) { if (arr == null) { return null; } int[] copy = new int[arr.length];//新建一个数组 for (int i = 0; i < arr.length; i++) { copy[i] = arr[i];//遍历拷贝 } return copy; } public static void main(String[] args) { int[] arr1 = {1,2,3,4,5,6,7,8,9}; System.out.println("数组1:"); System.out.println(Arrays.toString(arr1)); int[] arr2 = copy(arr1); System.out.println("数组2:"); System.out.println(Arrays.toString(arr2)); }}
复制代码



当然 Java 中的Arrays


类有内置的拷贝方法:<font color = orange>



</font>复制指定的数组,用零截取或填充(如有必要),以便复制具有指定的长度。


<font color = orange>



</font>将指定数组的指定范围[from, to)


复制到新数组中。<font color = orange>



</font>Object src表示源数组,srcPos表示从源数组开始拷贝的下标位置,Object dest表示目标数组,destPos表示表示从目标数组开始拷贝的下标位置,length表示拷贝数组元素个数。如果细心去查看该方法源代码,会发现该方法被native修饰,这个表示这个方法是使用C/C++


实现的。将指定源数组中的数组从指定位置复制到目标数组的指定位置。<font color = orange>



</font>


最后一种就是利用数组名.clone创建并返回此对象的副本。 “复制”的精确含义可能取决于对象的类。因为数组实例化后就是一个对象,该方法会返回值为对应类型的数组,所以使用该方法进行拷贝。


import java.util.Arrays;
public class Copy {
public static void main(String[] args) { int[] arr1 = {1,2,3,4,5,6,7,8,9}; System.out.println("arr1:" + Arrays.toString(arr1)); int[] arr2 = Arrays.copyOf(arr1, arr1.length); System.out.println("arr2:" + Arrays.toString(arr2)); int[] arr3 = Arrays.copyOf(arr1, arr1.length * 2); System.out.println("arr3:" + Arrays.toString(arr3)); int[] arr4 = Arrays.copyOfRange(arr1, 1, 5); System.out.println("arr4:" + Arrays.toString(arr4)); int[] arr5 = new int[arr1.length]; System.arraycopy(arr1, 0, arr5, 0, arr1.length); System.out.println("arr5:" + Arrays.toString(arr5)); int[] arr6 = arr1.clone(); System.out.println("arr6:" + Arrays.toString(arr6)); }}
复制代码



另外,一般来说数组的拷贝是浅拷贝,因为 Java 中万物皆对象,对对象的拷贝就是浅拷贝,而数组也是一种对象,除非人为因素使实现深拷贝,如果数组中的为简单的数据类型一般都是深拷贝,如果数组中为引用类型一般都是浅拷贝。

🎳3.3 数组转换字符串

再上述代码展示中我相信大家已经看到了Arrays.toString方法的使用,它能将一个数组转换成带中括号字符串!现在我们来模拟一下这个方法:


public class StringArray {    public static String myToString(int[] arr) {        if (arr == null) {            return "[]";//空引用返回[]        }        String str = "[";//初始化字符串为[        for (int i = 0; i < arr.length - 1; i++) {            str += arr[i] + ",";//注意最后一个数组元素后无逗号        }        str += arr[arr.length - 1] + "]";//查漏补缺,补上最后一个元素和]        return str;    }    public static void main(String[] args) {    int[] arr = {1,2,3,4,5,6,7,8,9};        System.out.println(myToString(arr));    }}
复制代码


🎳3.4 数组查找

⛳️3.4.1 顺序查找

顺序查找是最简单的查找方法,直接遍历一遍数组就可以了。


public class Search {    public static void main(String[] args) {        //顺序查找元素,找到其下标,未找到则输出未找到        int[] arr = {1,2,3,4,5,6,7,8,9};        int k = 7;        int flag = 0;        for (int i = 0; i < arr.length; i++) {            if (arr[i] == k) {                System.out.println("找到了!下标为:" + i);                flag = 1;                break;            }        }        if (flag == 0) {            System.out.println("未找到!");        }    }}
复制代码


⛳️3.4.2 二分查找

然后就是我们已经非常熟悉的二分查找:


public class BinSearch {    public static int binSearch(int[] arr, int k) {        if (arr == null) {            return -1;        }        int left = 0;        int right = arr.length - 1;        int mid = left + (right - left) / 2;        while (left <= right) {            mid = left + (right - left) / 2;            if (k > arr[mid]) {                left = mid + 1;            }            else if (k < arr[mid]) {                right = mid - 1;            }            else {                return mid;            }        }        return -1;    }    public static void main(String[] args) {        int[] arr = {1,2,3,4,5,6,7,8,9};        int k = 7;        System.out.println(binSearch(arr, k));    }}
复制代码


🎳3.5 数组的排列

⛳️3.5.1 判断数组是否有序

使用两个计数棋进行计数(从 1 开始计数),遍历数组分别对数组前一项不小于后一项,数组后一项不小于前一项独立计数,如果计数结果有刚好等于数组长度的结果则数组有序。


public class ArraryOrder {    public static boolean arrOrder(int[] arr) {        if (arr == null) {            return false;        }        int cnt1 = 1;        int cnt2 = 1;        for (int i = 0; i < arr.length - 1; i++) {            if (arr[i] <= arr[i+1]) {                cnt1++;            }            if (arr[i] >= arr[i+1]) {                cnt2++;            }        }        if (cnt1 == arr.length || cnt2 == arr.length) {            return true;        }        else {            return false;        }    }    public static void main(String[] args) {        int[] arr1 = {1,2,3,4,5,6,7,8,9};        int[] arr2 = {9,8,7,6,5,4,3,2,1};        int[] arr3 = {2,1,4,7,5,9,8,3,6};        System.out.println(arrOrder(arr1));        System.out.println(arrOrder(arr2));        System.out.println(arrOrder(arr3));    }}
复制代码


⛳️3.5.2 数组逆序

双指针,依次将左边元素与右边元素互换。


import java.util.Arrays;
public class ReverseArr { public static void rever(int[] arr) { if (arr == null) { return; } int l = 0; int r = arr.length - 1; while (l < r) { int tmp = arr[l]; arr[l] = arr[r]; arr[r] = tmp; l++; r--; } }
public static void main(String[] args) { int[] arr = {1,2,3,4,5,6,7,8,9}; System.out.println("逆序前:"); System.out.println(Arrays.toString(arr)); System.out.println("逆序后:"); rever(arr); System.out.println(Arrays.toString(arr)); }}
复制代码


⛳️3.5.3 冒泡排序(升序)

从数组首位元素开始将数组的相邻两个元素进行比较,如果前面的元素比后面大,则进行交换否则不交换,每进行一趟排序就能将一个最大的数放在最后,如果需要把所有元素都排好序,需要进行数组元素个数减一趟排序。因为每一趟排序都会排出一个最大的数放在后面,也就是说每排序一趟就有一个数排序完成,所以每完成一趟排序,排序比较次数就减一,假设数组元素个数为size,则一共要进行size-1趟排序,第 1 趟排序比较次数为size-1,随着趟数比较次数逐次递减,如果此时为第i趟排序,则需要比较的次数为size - 1 - i。比如 10 个元素进行冒泡排序,一共要进行 9 趟排序,第一趟需排序比较 9 次,第二趟 8 次,第三趟 7 次,以此类推。


import java.util.Arrays;
public class BubbleSort { public static void bubbleSort(int[] arr) { if (arr == null) { return; } for (int i = 0; i < arr.length - 1; i++) { int flag = 0; for (int j = 0; j < arr.length - 1 - i; j++) { if (arr[j] > arr[j+1]) { int tmp = arr[j]; arr[j] = arr[j+1]; arr[j+1] = tmp; flag = 1; } } if (flag == 0) { break; } } } public static void main(String[] args) { int[] arr = {2,1,8,5,9,4,6,7,3}; System.out.println("排序前:"); System.out.println(Arrays.toString(arr)); bubbleSort(arr); System.out.println("排序后:"); System.out.println(Arrays.toString(arr)); }}
复制代码


🎨4.二维数组

二维数组本质上也就是一维数组, 只不过每个元素又是一个一维数组.



前面我们知道了,我们是使用引用来指向一个数组的,那么二维数组其实一个类型为引用的数组,数组中的每个元素都是一个引用变量,引用变量中指向另一个一维数组。



二维数组定义:



数组名称.length;//表示行数数组名称[行数].length;//表示某一行的列数
复制代码


public class TestBolg {    public static void main(String[] args) {        int[][] arr = new int[3][3];        for (int i = 0; i < arr.length; i++) {            for (int j = 0; j < arr[i].length; j++) {                arr[i][j] = 8 + i +j;            }        }        for (int i = 0; i < arr.length; i++) {            System.out.println(Arrays.toString(arr[i]));        }    }}
复制代码



同理, 还存在 "三维数组", "四维数组" 等更复杂的数组。

发布于: 刚刚阅读数: 3
用户头像

未见花闻

关注

坚持+努力=诗+远方 2021.11.15 加入

一位热爱技术热爱分享的大学生!

评论

发布
暂无评论
批量处理数据神器——Java数组与引用_7月月更_未见花闻_InfoQ写作社区