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

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

1、数组的基本概念

1.1 我们为什么需要数组

假设说我们要存每个同学的期末考试总成绩,如果我们还不知道数组的话,那我们是不是得新建100个变量,而且赋值和打印也相当的麻烦, 而且我们发现成绩的数据类型都是一样的,所以就会有数组这个概念,数组即是相同类型元素的集合,而且是一块连续的存储空间,每个空间都有编号,也就是我们口中常说的数组下标。而且使用数组,也可以是代码变得更简化,方便的进行排序查找等,现在,我们就来进入数组的学习把:

1.2 数组的创建与初始化

我们这期是由浅到深讲解的,所以在前边有一些不理解的问题,请坚持往后看,会得到解决的。

在Java中对数组的创建并初始化有两种方式,分别是静态初始化和动态初始化:

public static void arrayInit() {
        int[] array1 = { 1,2,3,4,5,6,7,8,9,10 }; //静态初始化
        int[] array2 = new int[] { 1,2,3,4,5,6,7,8,9,10 }; //静态初始化
    }

这两种写法有什么不同呢?第一种虽然省去了 new int[ ],但是在编译的时候还是会还原成第二种方式,这两种写法本质上没有区别,都是在JVM栈上开辟一个 array1和array2元素,同时也会在堆上开辟两个一维数组,这两个变量分别存这这两个数组的地址,当然,这里你不懂没关系,后面我们也会画图一一讲解到,你只需要知道,这两种定义并初始化的方式只是写法上的不同就可以了!

那定义了数组但是不初始化呢?

public static void arrayInit() {
        int[] array3 = new int[10]; //动态初始化
        int[] array4 = null;
    }

如果是上面这种创建但是不初始化,array3 里面会默认初始化成0,也就是说,如果数组中存储的元素为基本类型,默认值为基本类型对对应的默认值0,像 array4 赋值成 null 这种情况,就可以理解成这个数组没有引用任何对象,这个地方听不懂没关系,往后看就能懂了。

image.png

不知道学过C语言的小伙伴还记不记得,C语言数组是可以不完全初始化的,比如说你一个数组5个元素,你只初始化前三个元素,在C语言中后续未初始化的元素会默认补0,但是在Java中你就算完全初始化了,如果你指定了元素个数的话,也会报错,只有在使用 new int[10],动态初始化的时候才能写明数组元素个数,你们也可以下来自己试试。

在Java的数组中,我们有几点需要注意:

  • 数组 { } 里面的元素类型一定要跟 [ ] 前面的类型保持一致
  • 静态初始化的时候不能指定长度,动态初始化的时候 new int[10]需要指定长度
  • 虽然没有指定数组长度,但是编译器在编译的时候会根据 { } 里面的元素个数来确定数组的长度
  • 虽然Java数组可以写成跟C语言一样的写法 int array[ ],但不推荐,因为这样语义不明确!
  • new int[n] ,[ ]中可以是变量

这里有小伙伴就有个小问题了,如果我定义了但是没有初始化,我能不能在下面重新赋值呢?

public static void arrayInit() {
        int[] array3;
        array3 = { 1,2,3,4,5 };
    }

这样是绝对不可以的,虽然你现在可能不是很理解,但我们前面有提过,数组变量 array3 里面放的是地址,这个在下面我们会细讲。这里你知道即可。

那如何正确的在定义之后初始化呢?或者重新赋值呢?

public static void arrayInit() {
        int[] array1;
        array1 = new int[10];
        int[] array2;
        array2 = new int[]{ 1,2,3,4,5 };   
    }

像如上代码这样是ok的,本质上其实就是在堆区创建了一个新对象,这个我们还是在后面细讲,这里让你们先见一见,为后面细节学习作铺垫。

1.3 数组的使用

数组是定义好了,我们如何去使用他呢?在前面我们提到过,数组是一块连续的内存空间,都有对应的编号,也就是下标,我们就可以通过下标的方式快速访问数组的任意位置的元素:

public static void main(String[] args) {
        int[] array = { 1,2,3,4,5 };
        array[2] = 88;
        System.out.println(array[2]);
    }

同时也可以对下标的值进行修改,但是这里我们要注意几点,数组的下标是从 0 开始的,所以最后一个元素下标应该是 n-1,也就是Java中大部分采用的都是左闭右开的,即:[ 0,n )

如果我们下标越界访问了,不用担心,程序会直接剖出下标越界异常,我们根据报错提示去找对应的位置即可。

1.4 数组的遍历

在Java中对数组其实有三种遍历打印的方式,每一种的情况都会讲明优缺点,接着往下看:

for 循环打印:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = { 1,2,3,4,5 };
        for (int i = 0; i < array.length; i++) {
            System.out.print(array[i] + " ");
        }
        System.out.println();
    }
}

这种方式是很常规的通过下标遍历访问的方式,对于数组的长度我们可以通过,数组对象.length 来获取数组的长度。

for-each 循环打印:

public class TestDemo {
    public static void main(String[] args) {
        int[] array = { 1,2,3,4,5 };
        for (int a : array) {
            System.out.print(a + " ");
        }
        System.out.println();
    }
}

这种打印方式呢,在 for 循环里冒号的左边必须是你要打印的数组里元素的类型定义的变量,右边则是你要打印数组的数组名,下面就可以通过你定义的变量进行打印了。for-each是for循环的另一种使用方式,他能在代码上更简洁,也可以避免循环条件和更新语句的书写错误,但是这样也有缺陷,比如说这种方式并不能拿到数组的下标。

Arrays工具类打印

public class TestDemo {
    public static void main(String[] args) {
        int[] array = { 1,2,3,4,5 };
        String ret = Arrays.toString(array); //既然返回的是字符串,我们就用字符串类型来接收
        System.out.println(ret);
        System.out.println(Arrays.toString(array)); //既然有返回值,那我们也可以直接链式访问
    }
}

首先我们要介绍下Arrays,他是在 java.util 包下的一个工具类,里面定义了很多对数组的操作方法,而 Arrays.toString 他的作用是把数组转换成字符串并返回,所以严格意义上它并不是遍历数组,只是把数组转化成对应的字符串而已。

以上三种方式各有优缺点,初学者结合实际情况作应用

2、引用类型数组的深入讲解

2.1 简单了解 JVM 的内存分布

Java的程序需要运行在虚拟机上的,如果对于内存中的数据随意存储的话,那以后对内存管理起来将会是很麻烦的一件事,所以JVM也对所使用的内存按照不同的功能进行了划分:

但是我们今天只重点关心堆和虚拟机栈这两块空间,在后续学习中会依次详细介绍这里面的内容:

虚拟机栈:与方法调用相关的一些信息,每个方法在执行的时候都会先创建一个栈帧,栈帧中包含:局部变量,操作数栈,动态链接,返回地址,以及一些其他的信息,保存的都是与方法执行相关的一些信息,比如:局部变量,当方法运行结束了后,栈帧也被销毁,即栈帧中保存的数据也被销毁了

堆:它是JVM管理的最大内存区域,使用 new 创建的对象都是在堆上保存的,堆是随着程序的开始而创建,随着程序的退出而销毁,堆中的数据只要还有在使用,就不会被销毁。

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

对这个理解特别重要,很关系到你后面进行学习,首先我们要区别这个两个的区别,先说基本类型变量,这种变量中直接存放的是所对应的值,而引用类型创建的变量,一般称为对象的引用,这种变量里存储的是对象所在空间的地址,下面我们用一小段代码,并且画图让大家理解的更清楚:

public class TestDemo {
    public static void main(String[] args) {
        int a = 10;
        int b = 20;
        int[] array = { 1,2,3,4,5 };
    }
}

其实看到这张图,相信大家就能很好的理解了,其实我们引用变量并不是存储了对象本身,只是存储了对象的其实地址,那我们的 array 只是存储了在堆中开辟的一维数组的地址!并没有把整个数组都保存在变量中!通过该对象的地址,引用变量就可以去操作这个对象了!

相关文章
|
3月前
|
Java
Java 数组学习笔记
本文整理Java数组常用操作:遍历、求和、查找、最值及二维数组行求和等典型练习,涵盖静态初始化、元素翻倍、去极值求平均等实例,帮助掌握数组基础与应用。
|
3月前
|
安全 Java API
Java SE 与 Java EE 区别解析及应用场景对比
在Java编程世界中,Java SE(Java Standard Edition)和Java EE(Java Enterprise Edition)是两个重要的平台版本,它们各自有着独特的定位和应用场景。理解它们之间的差异,对于开发者选择合适的技术栈进行项目开发至关重要。
466 1
|
4月前
|
存储 缓存 Java
Java数组全解析:一维、多维与内存模型
本文深入解析Java数组的内存布局与操作技巧,涵盖一维及多维数组的声明、初始化、内存模型,以及数组常见陷阱和性能优化。通过图文结合的方式帮助开发者彻底理解数组本质,并提供Arrays工具类的实用方法与面试高频问题解析,助你掌握数组核心知识,避免常见错误。
|
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
|
7月前
|
存储 人工智能 Java
打乱数组内容引发的问题( Java)
本文介绍了两种实现数组随机打乱的方法,并深入探讨了Java中原始数据类型与对象类型的差异。方法一通过自定义随机数交换数组元素位置,方法二借助`Collections.shuffle()`函数完成数组打乱。同时,文章详细解析了`int`和`Integer`的区别,包括声明方式、内存占用、初始化以及对象特性等,并讲解了自动装箱与拆箱的功能,帮助读者更好地理解Java的基础知识。
138 0
|
8月前
|
存储 Java 数据挖掘
Java 中数组的多种定义方式
本文深入解析了Java中数组的多种定义方式,涵盖基础的`new`关键字创建、直接初始化、动态初始化,到多维数组、`Arrays.fill()`方法以及集合类转换为数组等高级用法。通过理论与实践结合的方式,探讨了每种定义方法的适用场景、优缺点及其背后的原理,帮助开发者掌握高效、灵活的数组操作技巧,从而编写更优质的Java代码。
421 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的转换
|
9月前
|
存储 Java 索引
Java 复制数组
本文介绍了Java中数组的基础知识与常用操作,包括数组的概念、创建、访问元素、遍历、复制、排序和搜索等方法。同时详细讲解了数组的五种赋值方式,并通过代码示例演示了求总和平均值、最大最小值、升序降序排序及Arrays类的常用方法。内容深入浅出,适合初学者学习掌握Java数组的核心功能与应用场景。
136 2