• JavaSE - 数组的定义、使用、内存分布、应用


    目录

    1. 数组的定义

    2. 数组的使用

    2.1 访问数组

    2.2 遍历数组

    2.3 练习:改变原有数组元素的值

    3. 数组是引用类型

    3.1 内存分布 

    3.1.1 初始JVM的内存分布

    3.1.2 与C语言的内存分布简单做个对比

    3.1.3 在Java和C中数组存储位置有什么区别吗?

    3.2 基本类型变量与引用类型变量的区别 

    3.3 通过一些题进一步理解引用

    题目一:

    题目二:

    ​题目三:

    4. 数组的应用(引用/数组名的应用)

    4.1 保存数据

    4.2 作为函数的参数

    4.2.1  

    4.2.2 交换两个值:

    4.3 作为函数的返回值

    5. 数组的练习:  Arrays -> 操作 数组相关的 工具类

    5.1 数组转字符串:Arrays.toString(数组名) 

    5.2 数组拷贝: Arrays.copyOf()  、  Arrays.copyOfRange()                                         需要拷贝的数组.clone()    、 arraycopy 

    5.2.1 Arrays.copyOf(original,new length)

    5.2.2 Arrays.copyOfRange(original,from,to) 

    5.2.3 需要拷贝的数组 . clone()

    5.2.4 arraycopy

    (要拷贝哪个数组,

    从哪个位置开始拷,

    往哪个数组里拷,

    拷贝到数组的哪个位置,

    拷多长)

    5.2.5 自己实现一个数组拷贝

    5.3 查找数组中指定元素:顺序查找、二分查找

    5.3.1按顺序查找

    5.3.2 Arrays.binarySearch(要查找的数组,要查找的元素)

    5.3.3 自己实现一个二分查找

    5.4 数组排序

    5.4.1 Arrays.sort(数组名)

    5.4.2 冒泡排序

    5.5 比较两个数组是否相等:Arrays.equals(数组名1,数组名2)

    5.6 给数组初始化:Arrays.fill()

    5.6.1 全部初始化为同一个值:Arrays.fill(需要初始化的数组,初始化成的值)

    5.6.2 部分初始化为同一个值:Arrays.fill(要初始化的数组,from,to,初始化成的值)

    5.7 数组逆序

    6. 二维数组

    6.1 二维数组的定义

    6.2 数组的使用

    6.2.1 二维数组是特殊的一维数组

    6.2.2 一维数组和二维数组在内存中存储的对比图

     6.2.3 遍历二维数组

    6.3 不规则的二维数组 


    1. 数组的定义

    数组是一块连续的存储空间,存储的是一组相同类型的元素。

    在Java当中,如果定义了一个数组,分配了内存大小,但没有进行初始化。那么数组元素会有一个默认值。

    2. 数组的使用

    2.1 访问数组

    2.2 遍历数组

    1. public class TestDemo {
    2. public static void main(String[] args) {
    3. //遍历数组
    4. int[] array = {1,2,3,4};
    5. //(!!!)方法一:for循环
    6. for (int i = 0; i < array.length; i++) {
    7. System.out.print(array[i]+" ");
    8. }
    9. System.out.println();
    10. //(!!!)方法二:foreach也叫作增强for循环 (数组中每个元素的类型定义的一个变量:数组名)
    11. //可以这样理解:遍历array,每拿到一个元素,就存到x中,然后再将x打印出来
    12. for (int x:array) {
    13. System.out.print(x+" ");
    14. }
    15. System.out.println();
    16. //方法一和方法二的区别:foreach是拿不到数组下标的,for循环可以拿到数组下标
    17. //(!!!)方法三:Arrays.toString(数组名)
    18. /* Java当中有一个工具,可以专门用来操作数组,这个工具叫做Arrays。
    19. (用它需要导入包:import java.util.Arrays;)*/
    20. /*toString:返回指定数组的内容的字符串形式
    21. * 把数组转变为字符串形式,然后返回*/
    22. String ret = Arrays.toString(array);
    23. System.out.println(ret);
    24. }
    25. }

    2.3 练习:改变原有数组元素的值

    实现一个方法 transform, 以数组为参数, 循环将数组中的每个元素 乘以 2 , 并设置到对应的数组元素上. 例如 原数组为 {1, 2, 3}, 修改之后为 {2, 4, 6}

    1. public class TestDemo2 {
    2. public static void transform(int[] array){
    3. for (int i = 0; i < array.length; i++) {
    4. array[i] *= 2;
    5. }
    6. }
    7. public static void main(String[] args) {
    8. Scanner scan = new Scanner(System.in);
    9. int n = scan.nextInt();
    10. int[] array = new int[n];
    11. //给数组赋值不能使用foreach,目前知识储备做不到
    12. //foreach一般用于遍历数组,输出数组元素
    13. /* for (int x:array) {
    14. x = scan.nextInt();
    15. }*/
    16. //用for循环来做
    17. for (int i = 0; i < n; i++) {
    18. array[i] = scan.nextInt();
    19. }
    20. transform(array);
    21. for (int x:array) {
    22. System.out.print(x+" ");
    23. }
    24. }
    25. }

     

    总结: 遍历输出数组内容可以考虑for循环foreach,但是给数组初始化用for循环,因为foreach拿不到数组的下标,且目前我的知识储备做不到。

    3. 数组是引用类型

    3.1 内存分布 

    3.1.1 初始JVM的内存分布

    JVM对所使用的内存按照功能的不同分为:程序计数器,虚拟机栈,本地方法栈,堆和方法区。

    先简单了解一下虚拟机栈和堆。

    虚拟机栈:与方法调用相关的一些信息,比如局部变量等。每个方法在执行时,都会先创建一个栈帧。当方法运行结束后,栈帧就被销毁了,即栈帧中保存的数据也被销毁了。

    堆:使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2, 3} )。堆是随着程序开始运行时而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销 毁。

    方法区:常量,静态变量等。


    3.1.2 与C语言的内存分布简单做个对比

    C语言也有5大内存分区:栈区,堆区,全局/静态存储区,文字常量区,程序代码区

    栈区:局部变量 函数的形参 每一次函数调用都会在栈区上申请空间

    堆区:动态内存管理,malloc,free,calloc,realloc

    全局/静态存储区:静态变量,全局变量

    文字常量区:常量


    3.1.3 在Java和C中数组存储位置有什么区别吗?

    • Java中,数组就是对象,是在堆上保存的。对象会有一个地址,地址存在引用变量中,引用变量是一个局部变量,存储在栈上。
    • C语言中,数组在{}内创建,此变量就是局部变量,此时数组就在栈区上;在{}外创建,此变量就是全局变量,此时数组在静态区上。

    3.2 基本类型变量与引用类型变量的区别 

    基本数据类型创建的变量,称为基本变量,该变量空间中直接存放的是其所对应的值

    引用数据类型创建的变量,一般称为对象的引用,其空间中存储的是对象所在空间的地址

     

    数组是对象,对象存储在堆上,会存在一个地址。

    array是引用,存储在栈上,里面放的是对象的地址。

    通过地址,就能找到对象,进行打印或修改。

    若在main函数里,定义一个数组,main函数结束后,引用变量就会被内存回收,但它指向的对象不一定会被内存回收。对象的回收,是没人引用它。

    图解: 

    3.3 通过一些题进一步理解引用

    题目一:

    1. import java.util.Arrays;
    2. public class TestDemo {
    3. public static void main(String[] args) {
    4. int[] array = {1,2,3,4};
    5. System.out.println(Arrays.toString(array));
    6. int[] array2 = array;
    7. array2[1] = 99;
    8. System.out.println(Arrays.toString(array));
    9. System.out.println(Arrays.toString(array2));
    10. }
    11. }

    题目二:

    1. public class TestDemo {
    2. public static void main(String[] args) {
    3. int[] array = {1,2,3,4};
    4. int[] array2 = {4,5,6,7};
    5. array = array2;
    6. System.out.println(Arrays.toString(array));
    7. System.out.println(Arrays.toString(array2));
    8. }
    9. }

    题目三:

    4. 数组的应用(引用/数组名的应用)

    传的都是数组名,数组名中存的地址,是对象在堆上的地址,通过数组名就可以找到对象了。

    4.1 保存数据

    可以用for循环,foreach,Arrays.toString()输出数组内容

    4.2 作为函数的参数

    在Java中,拿不到栈上的地址,只能拿到堆上的地址,就是这么规定的。

    4.2.1  

    1. public class TestDemo {
    2. public static void func1(int[] array1){
    3. array1 = new int[10];
    4. }
    5. public static void func2(int[] array2){
    6. array2[0] = 99;
    7. }
    8. public static void main(String[] args) {
    9. int[] array = {1,2,3,4};
    10. func1(array);
    11. System.out.println(Arrays.toString(array));
    12. func2(array);
    13. System.out.println(Arrays.toString(array));
    14. }
    15. }

     

    4.2.2 交换两个值:

    4.3 作为函数的返回值

    5. 数组的练习:  Arrays -> 操作 数组相关的 工具类

    5.1 数组转字符串:Arrays.toString(数组名) 

    Arrays.toString(数组名) :把数组转变为字符串形式,然后返回。

    有返回值,需要变量接收。

    下面模拟实现一个toString:

    1. public class TestDemo {
    2. /*自己实现一个toString - myToString
    3. * 将数组转变为字符串形式,然后输出
    4. */
    5. public static String myToString(int[] array){
    6. if(array == null){//先判断array是不是为null!!!
    7. return "null";
    8. }
    9. String ret = "[";
    10. for (int i = 0; i < array.length; i++) {
    11. ret += array[i];
    12. if(i< array.length-1){
    13. ret += ",";
    14. }
    15. }
    16. ret += "]";
    17. return ret;
    18. }
    19. public static void main(String[] args) {
    20. int[] array =null;
    21. String ret = myToString(array);
    22. System.out.println(ret);
    23. int[] array2 ={1,2,3,4};
    24. String ret2 = myToString(array2);
    25. System.out.println(ret2);
    26. }
    27. }

    5.2 数组拷贝: Arrays.copyOf()  、  Arrays.copyOfRange()                                         需要拷贝的数组.clone()    、 arraycopy 

    5.2.1 Arrays.copyOf(original,new length)

    因为new length新的长度int类型的,所以只能是整数倍,不能是小数倍

    有返回值,需要变量接收。

    看源码:鼠标定位到+ctrl+鼠标左键   或    鼠标定位到ctrl+b

    看方法索引:alt+7

    5.2.2 Arrays.copyOfRange(original,from,to) 

    但它是左闭右开的,最后那个数不在拷贝范围内。此方法支持局部拷贝

    有返回值,需要变量接收。

    5.2.3 需要拷贝的数组 . clone()

    相当于产生一个副本

    有返回值,需要变量接收。

    5.2.4 arraycopy

    (要拷贝哪个数组,

    从哪个位置开始拷,

    往哪个数组里拷,

    拷贝到数组的哪个位置,

    拷多长)

    arraycopy使用特别自由。但是使用前别忘记先定义一个数组来放拷贝后的数据。

    没有返回值,不需要变量接收。

    5.2.5 自己实现一个数组拷贝

    1. public class TestDemo {
    2. public static void main(String[] args) {
    3. int[] array = {1,3,5,7,9};
    4. int[] array2 = new int[array.length];//Java中 new int[],[]中允许写变量
    5. for (int i = 0; i < array.length; i++) {
    6. array2[i] = array[i];
    7. }
    8. System.out.println(Arrays.toString(array));
    9. System.out.println(Arrays.toString(array2));
    10. }
    11. }

     

    5.3 查找数组中指定元素:顺序查找、二分查找

    5.3.1按顺序查找

    使用for循环遍历数组,找到返回下标,找不到返回-1

    5.3.2 Arrays.binarySearch(要查找的数组,要查找的元素)

    二分查找法:只针对有序数组

    有返回值,需要变量接收。默认找到返回下标,找不到返回负数

    5.3.3 自己实现一个二分查找

    二分查找法:只针对有序数组

    1. public class TestDemo {
    2. public static int binarySearch(int[] array,int k){
    3. //二分查找
    4. int left = 0;
    5. int right = array.length-1;
    6. while(left<=right){
    7. int mid = left+((right - left)>>1);
    8. if(k
    9. right = mid - 1;
    10. }else if(k>array[mid]){
    11. left = mid +1;
    12. }else{
    13. return mid;
    14. }
    15. }
    16. return -1;
    17. }
    18. public static void main(String[] args) {
    19. int[] array = {1,3,5,7,9,13};
    20. Scanner scan = new Scanner(System.in);
    21. int k = scan.nextInt();
    22. int ret = binarySearch(array,k);
    23. if(ret == -1){
    24. System.out.println("找不到");
    25. }else{
    26. System.out.println("找到了,下标为:"+ret);
    27. }
    28. }
    29. }

    5.4 数组排序

    5.4.1 Arrays.sort(数组名)

    默认排成升序

    没有返回值,不需要变量接收。

    5.4.2 冒泡排序

    1. public class TestDemo {
    2. //数组排序
    3. //冒泡排序
    4. public static void bubbleSort(int[] array){
    5. //趟数
    6. for (int i = 0; i < array.length-1; i++) {
    7. boolean flag = true;
    8. //交换
    9. for (int j = 0; j < array.length-1-i; j++) {
    10. if(array[j]>array[j+1]){
    11. int tmp = array[j];
    12. array[j] = array[j+1];
    13. array[j+1] = tmp;
    14. flag = false;
    15. }
    16. }
    17. if(flag == true) {
    18. return;
    19. }
    20. }
    21. }
    22. public static void main(String[] args) {
    23. int[] array = {9,8,7,6,5,4,3,2,1,0};
    24. bubbleSort(array);
    25. System.out.println(Arrays.toString(array));
    26. }
    27. }

    5.5 比较两个数组是否相等:Arrays.equals(数组名1,数组名2)

    有返回值,需要变量接收。默认相等返回true,不相等返回false

    5.6 给数组初始化:Arrays.fill()

    没有返回值,不需要变量接收。

    5.6.1 全部初始化为同一个值:Arrays.fill(需要初始化的数组,初始化成的值)

    5.6.2 部分初始化为同一个值:Arrays.fill(要初始化的数组,from,to,初始化成的值)

    左闭右开 

    5.7 数组逆序

    1. public class TestDemo {
    2. public static void reserve(int[] array){
    3. int left = 0;
    4. int right = array.length - 1;
    5. while(left
    6. int tmp = array[left];
    7. array[left] = array[right];
    8. array[right] = tmp;
    9. left++;
    10. right--;
    11. }
    12. }
    13. public static void main(String[] args) {
    14. int[] array = {1, 2, 5, 6, 9, 17, 26, 47, 88, 94};
    15. reserve(array);
    16. System.out.println(Arrays.toString(array));
    17. }
    18. }

    6. 二维数组

    6.1 二维数组的定义

    和一维数组的定义大差不差

    6.2 数组的使用

    6.2.1 二维数组是特殊的一维数组

    6.2.2 一维数组和二维数组在内存中存储的对比图

     6.2.3 遍历二维数组

    1. //遍历二维数组
    2. public static void main(String[] args) {
    3. int[][] array = {{1,2,3},{4,5,6}};
    4. //1、for循环
    5. for (int i = 0; i < array.length; i++) {
    6. for (int j = 0; j
    7. System.out.print(array[i][j]+" ");
    8. }
    9. System.out.println();
    10. }
    11. System.out.println();
    12. //2、foreach 增强for循环
    13. /*(数组中每个元素的类型定义的一个变量:数组名)
    14. * 一维数组中的每个元素也是一个一维数组*/
    15. for (int[] arr:array) {
    16. for (int x:arr) {
    17. System.out.print(x +" ");
    18. }
    19. System.out.println();
    20. }
    21. System.out.println();
    22. //3、Arrays.deepToString(数组名)
    23. System.out.println(Arrays.deepToString(array));
    24. }

    6.3 不规则的二维数组 

    列可以省略,后面可以指定它的列(即每个一维数组的长度)

    最后(提醒自己):

    一定要将Java和C分隔开,学Java时暂时忘记C,这是两种不同的语言,没必要追究为什么语法不同,因为本来设计就不同。

    就像同一个汉字 “我”,在不同地区方言念法不同,这是两种不同的方言,你非要追究为什么在我这“我”是这样念的,在你那就不一样了呢。没有可比性,这本来就是两种不同的方言,它们的共性只有一点,都是语言。

    Java和C也是这样,它们是两种不同的计算机语言,本来就不一样。

  • 相关阅读:
    8.2 JUC - 4.Semaphore
    聊聊 HTTP 性能优化
    VISUAL STUDIO调试器指南---断点和跟踪点
    还没用熟 TypeScript 社区已经开始抛弃了
    With As多表查询
    SQL Server外键约束
    okcc坐席进线太慢,怎么办?
    Docker安装Redis 7.x单机模式
    基于springboot财务管理系统
    SimpleServletHandlerAdapter类简介说明
  • 原文地址:https://blog.csdn.net/m0_61731585/article/details/126093517