【Java SE】数组的深入理解(下)

简介: 假设说我们要存每个同学的期末考试总成绩,如果我们还不知道数组的话,那我们是不是得新建100个变量,而且赋值和打印也相当的麻烦, 而且我们发现成绩的数据类型都是一样的,所以就会有数组这个概念,数组即是相同类型元素的集合,而且是一块连续的存储空间,每个空间都有编号,也就是我们口中常说的数组下标。

2.3 通过方法更深刻理解引用变量

有了上面的认识,我们就要来理解下面这两个方法的作用了,相信你看完会有更深刻的认识:

是不是结果可能跟你想得有点不一样呢?不用担心,我们来一个个分析下:

首先我们执行的是 func1 我们知道 array 变量中存的是一个对象的地址,那么通过传参给 func1 的 arr1,首先要建立栈帧,把 array 存的地址拷贝到 arr1 当中,这样一来就相当于 arr1 也指向了那个变量,但是我们又 new 了一个对象,并把新对象的地址赋值给了 arr1,相当于 arr1  原来存放的地址已经被替换了,也就说 arr1 指向了一个新的对象,因为只是把 array 存的地址拷贝给了 arr1 所以执行完 func1 这个方法之后,array 并不会受任何影响,当方法结束,arr2 变量销毁,因为arr2 销毁之后没有变量接着引用在 func1 中 new 的新对象,所以此时新的对象就被 JVM 回收了!

当我们执行完 func1 时,就是我们说的结果,所以 array 的值不受任何影响!

我们接着再来看执行 func2 之后的结果,首先前半部分与 func1 一样,都是传递的 array 指向对象的地址,但是 func2 里面语句是直接对 arr2 中对象的地址进行下标访问,修改了 [1] 下标处的值,因为本质 array 和 arr2 引用的都是同一个对象,当 arr2 修改了对象的值,所以当函数结束后接着打印 array 指向对象的值肯定也被修改了!方法结束,arr2 被销毁,但是 arr2 指向的对象仍然被 array 指向着,所以JVM不会回收此时的对象!

看到这,你肯定有了更深刻的理解,前面有疑问的地方肯定得到了解决,所谓的 "引用" 本质上只是存了一个地址,Java将数组设定成引用类型,这样后续进行数组传参,其实只是将数组的地址传入到形参当中,这样就可以避免对整个数组的拷贝!

在我们目前认识中,如果对象没有被引用,则会自动回收,所以不用考虑内存泄漏的问题

2.4 数组作为函数返回值

假设这里我们有一个题,需要实现一个方法,这个方法需要获取斐波那契数列的前 n 项,需要返回一个数组回来,本质其实就是返回数组的地址,如何实现呢?

public static int[] fib(int n) {
        if (n <= 0) {
            return null;
        }
        int[] array = new int[n];
        array[0] = array[1] = 1;
        for (int i = 2; i < n; i++) {
            array[i] = array[i - 1] + array[i - 2];
        }
        return array;
    }
    public static void main(String[] args) {
        int[] array = fib(8);
        System.out.println(Arrays.toString(array));
    }

当然这个方法如果 n 为1 就会越界,这个下来可以自己优化下,来到这里我们就来介绍下Arrays这个工具类里面的一些方法了: 像一些将数组转换成字符串,数组二分查找,数组排序等等,可以下来查阅下帮助手册,这里我就不细说了,交给大家自己去扩展了,如果以后用到,我会进行说明。

3、二维数组

3.1 二维数组的概念和内存布局

这里我们一定要有一个概念,二维数组是一个特殊的一维数组,如何理解呢?用文字来说,二维数组的每个元素是一维数组,也就是说,二维数组的每个元素里面放的是一维数组的地址!

相信听完上面的话,大家可能不是很理解,那我们就定义一个二维数组,并画图:

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

这里就很清晰明了了,图中也能看到,二维数组本质就是一个一维数组,只不过这个一维数组的每个元素存的是地址而已!

3.2 二维数组的定义和初始化

当然,二维数组和一维数组一样,同样的三种定义方式:

int[][] array1 = { {1,2,3}, {4,5,6} }; //两行三列的二维数组
int[][] array2 = new int[][]{ {1,2,3}, {4,5,6} };
int[][] array3 = new int[2][3];

如果只是单纯的 int[][] array; 这样数组里面没有任何引用对象,并不能直接使用未引用对象的数组,如果不引用最好置null

3.3 二维数组遍历

for 循环打印:

public class TestDemo {
    public static void main(String[] args) {
        int[][] array1 = { {1,2,3}, {4,5,6} }; //两行三列的二维数组
        for (int i = 0; i < array1.length; i++) {
            for (int j = 0; j < array1[i].length; j++) {
                System.out.print(array1[i][j] + " ");
            }
            System.out.println();
        }
        System.out.println();
    }
}

这里第一个 for 里面的长度求的是 array1.length,因为它本身就是一个特殊一维数组,这样求出的就是它的行,第二个for array1[i].length,自然求得就是每一行一维数组长度了

for-each 循环打印:

public class TestDemo {
    public static void main(String[] args) {
        int[][] array1 = { {1,2,3}, {4,5,6} }; //两行三列的二维数组
        for (int[] arr : array1) { //二维数组的每个元素是一维数组,所以每个元素的类型是int[]
            for (int a : arr) { //arr是一维数组,每个数组的元素的int
                System.out.print(a + " ");
            }
            System.out.println();
        }
    }
}

Arrays 工具类有个方法也可以打印二维数组,是Arrays.deepToString,这个方法也是打印二维数组的但只能在一行显示,感兴趣的可以下来自己实验下。

3.4 不规则的二维数组

在Java中,二维数组的列可以省略,也就是把二维数组看成一个特殊的一维数组的每个元素指向的一维数组是可以元素个数不同的,如何理解这句话呢?我们还是一样通过一小段并且以画图的形式给大家讲解:

int[][] array = new int[2][];
array[0] = new int[3];
array[1] = new int[2];

当然,他的遍历方法是跟普通二维数组一样的, 这里我就不多说,自己摸索,实在不懂可以问下博主。

相关文章
|
4月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
3月前
|
Java
Java 数组学习笔记
本文整理Java数组常用操作:遍历、求和、查找、最值及二维数组行求和等典型练习,涵盖静态初始化、元素翻倍、去极值求平均等实例,帮助掌握数组基础与应用。
|
3月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
466 1
|
5月前
|
存储 Java 索引
java 数组
在 Java 中,数组是一种数据结构,用于存储多个相同类型的数据元素。数组的大小一旦创建后就不能改变,因此它是固定长度的。Java 数组是一种 对象,即使它存储的值是基本类型(如 int、double 等),它也是一个对象引用。
159 0
|
6月前
|
设计模式 算法 Java
Java SE 与 Java EE 组件封装使用方法及实践指南
本指南详细介绍了Java SE与Java EE的核心技术使用方法及组件封装策略。涵盖集合框架、文件操作、Servlet、JPA、EJB和RESTful API的使用示例,提供通用工具类与基础组件封装建议,如集合工具类、文件工具类、基础Servlet、实体基类和服务基类等。同时,通过分层架构集成示例展示Servlet、EJB和JPA的协同工作,并总结组件封装的最佳实践,包括单一职责原则、接口抽象、依赖注入、事务管理和异常处理等。适合希望提升代码可维护性和扩展性的开发者参考。
212 0
|
9月前
|
人工智能 Java
Java 中数组Array和列表List的转换
本文介绍了数组与列表之间的相互转换方法,主要包括三部分:1)使用`Collections.addAll()`方法将数组转为列表,适用于引用类型,效率较高;2)通过`new ArrayList&lt;&gt;()`构造器结合`Arrays.asList()`实现类似功能;3)利用JDK8的`Stream`流式计算,支持基本数据类型数组的转换。此外,还详细讲解了列表转数组的方法,如借助`Stream`实现不同类型数组间的转换,并附带代码示例与执行结果,帮助读者深入理解两种数据结构的互转技巧。
651 1
Java 中数组Array和列表List的转换
|
7月前
|
存储 人工智能 Java
打乱数组内容引发的问题( Java)
本文介绍了两种实现数组随机打乱的方法,并深入探讨了Java中原始数据类型与对象类型的差异。方法一通过自定义随机数交换数组元素位置,方法二借助`Collections.shuffle()`函数完成数组打乱。同时,文章详细解析了`int`和`Integer`的区别,包括声明方式、内存占用、初始化以及对象特性等,并讲解了自动装箱与拆箱的功能,帮助读者更好地理解Java的基础知识。
138 0
|
9月前
|
存储 监控 Java
《从头开始学java,一天一个知识点》之:数组入门:一维数组的定义与遍历
**你是否也经历过这些崩溃瞬间?** - 看了三天教程,连`i++`和`++i`的区别都说不清 - 面试时被追问&quot;`a==b`和`equals()`的区别&quot;,大脑突然空白 - 写出的代码总是莫名报NPE,却不知道问题出在哪个运算符 这个系列就是为你打造的Java「速效救心丸」!我们承诺:每天1分钟,地铁通勤、午休间隙即可完成学习;直击痛点,只讲高频考点和实际开发中的「坑位」;拒绝臃肿,没有冗长概念堆砌,每篇都有可运行的代码标本。明日预告:《多维数组与常见操作》。 通过实例讲解数组的核心认知、趣味场景应用、企业级开发规范及优化技巧,帮助你快速掌握Java数组的精髓。
213 23
|
9月前
|
存储 Java 索引
Java 复制数组
本文介绍了Java中数组的基础知识与常用操作,包括数组的概念、创建、访问元素、遍历、复制、排序和搜索等方法。同时详细讲解了数组的五种赋值方式,并通过代码示例演示了求总和平均值、最大最小值、升序降序排序及Arrays类的常用方法。内容深入浅出,适合初学者学习掌握Java数组的核心功能与应用场景。
136 2