本文中使用到的工具是Intellij IDEA和JDK 8,需要安装两款工具的小伙伴请查看这两篇教程:点我查看安装JDK8教程、点我查看安装Intellij IDEA教程。
假设我想在某宝上买一点零食(没错,我承认我确实是个吃货),经过搜索后出现了如下结果,我们发现每一项都包含相同内容:图片、标题、价格、购买人数、所在店铺名称。要想将每一个数据项展现给用户,就需要一个特定的“容器”来存储每一个数据项。
在日常生活中,"容器"通常是指一种用于装载、储存物质的器具。例如:水杯可以装水,衣柜可以装衣物。
仿照日常生活中的“容器”的定义,我们可以给程序中的容器做个说明:多个数据项聚合在一起,组成了一个装载数据的容器。这个容器对数据项进行访问、修改等操作。
接下来要讲的数组就属于容器的一种。
一、数组的概念
数组的定义:数组是一种数据结构,它用于存储相同类型的元素(如整数、字符串等)的有序集合。
1.1 数组相关的概念
1. 数组名:基本数据类型变量存在变量名,那么数组也有数组变量,数组的变量名就是这个数组的名称。例如:numbers
代表这个数组存储的是数字。
2. 索引:数组中每一个元素都有唯一的索引(类似我们的身份证号),我们访问数组元素的值时会用到索引。数组的索引是有序的,这样做的好处是访问数组的元素非常快。
3. 元素:数组元素是数组的基本组成单位,元素的数据类型决定了数组的数据类型,相反,数组的数据类型也决定了每个元素的数据类型。
4. 数组的长度:数组中存储元素的数量。
5. 数组本身是引用数据类型。但是数组中的元素既可以是基本数据类型,也可以是引用数据类型。
6. 数组的大小是固定的,一旦创建,其大小就不能改变。
1.2 数组的划分
按照数据类型划分,数组可以分成基本类型数组、引用数据类型数组。以基本类型数组为例,每一个数组元素的数据类型都是基本数据类型。
按照维度划分,数组可以划分成一维数组、二维数组、三维数组……
- 一维数组中存储一组数据:
- 二维数组本质上就是一维数组的每个元素再存储一个数组,每个元素对应的数组存储元素个数可能也不尽相同(本质上就是一维数组再嵌套一维数组):
就我个人日常开发而言,使用一维数组的次数多一些,用到二维数组的次数就几乎很少了(在做算法题的时候能用的到)
备注:本文后续提到的数组默认都是一维数组。
二、定义并初始化数组
2.1 定义数组变量
定义数组变量有两种方式:
方式一:方括号写到数据类型的后面。
// Java风格定义数组变量 数据类型[] 变量名;
这里的数据类型既可以是基本数据类型,也可以是引用数据类型。例如,我想定义一个int
类型数组arr1
和String
类型数组arr2
,可以写成如下形式:
// int类型数组 int[] arr1; // 引用数据类型数组 String[] arr2;
方式二:如果你之前学过C或者C++的数组,也可以把方括号写到变量名后面。
数据类型 变量名[];
定义数组变量完成后,就需要创建数组了。创建数组一共有两种方式:静态初始化和动态初始化。
2.2 创建数组方式——静态初始化
静态初始化:数组中存储的内容已经确定,可以使用以下两种方式静态初始化:
数据类型[] 变量名 = new 数据类型[] {变量值1, 变量值2, 变量值3,..., 变量值n};
上述方式有简化写法,赋值符号右侧的new 数据类型[]
可以省略,只保留大括号中的内容,写法如下:
数据类型[] 变量名 = {变量值1, 变量值2, 变量值3,..., 变量值n};
下面代码展示了上述两种方式创建数组:
/** * 数组静态初始化两种方式 * * @author iCode504 * @date 2024-01-12 */ public class MyArrayDemo1 { public static void main(String[] args) { // new 数据类型[] {...}方式初始化数组 int[] array1 = new int[]{1, 2, 3, 4, 5}; double[] array2 = new double[]{4.2, 5.6, 7.6, 2.33, 8.88}; String[] tastyFoods = new String[]{"砂锅麻辣烫", "过桥米线", "土豆粉", "砂锅居", "火锅"}; // {...}方式初始化数组 float[] array3 = {2.3f, 89.66f, 34.2f, -20.33f}; long[] array4 = {666, 888, 999, 648}; String[] changchunAttractions = {"净月潭公园", "南湖公园", "伪满皇宫", "长影世纪城", "雕塑公园"}; } }
注意:使用花括号
{}
创建数组必须先定义数组变量的同时就将创建好的数组赋值给数组变量。先定义数组变量,再使用花括号的方式赋值是错误的,无法通过编译。以下是错误写法:
// 定义数组变量 int[] arr; // 以花括号的方式对应的数组值赋值给变量无法通过编译 arr = {1, 2, 3, 4, 5}; 在IDEA中这样写代码时,也会给出错误提示:
2.3 创建数组方式——动态初始化
前面讲到的静态初始化的方式创建数组有一个前提就是你已经确定数组中要存储什么。但是在大多数情况下,我们也不确定数组要存储什么,而是在后续的时候修改数组中元素的值,这时候我们就可以使用动态初始化的方式创建数组。
动态初始化:数组的长度可以确定,但是数组里面具体写什么内容还不确定,语法格式如下:
数据类型[] 变量名 = new 数据类型[n];
其中n指的是数组的长度,即数组中存储元素的数量。具体内容可以看下一部分:数组的长度。
以下是动态初始化方式创建数组:
/** * 动态初始化方式创建数组 * * @author iCode504 * @date 2024-01-13 */ public class MyArrayDemo2 { public static void main(String[] args) { // 动态初始化方式创建长度为4的char数组、String数组、int数组 char[] array1 = new char[4]; String[] array2 = new String[4]; int[] array3 = new int[4]; } }
三、数组的长度
假设有一个数组arr
,要想获取数组的长度,我们只需要使用arr.length
获取数组的长度即可。
长度为0的数组称作空数组。
定义数组时,数组的长度必须是整数且大于等于0,否则系统会抛出数组长度为负数(NegativeArraySizeException
)异常。
/** * 数组的长度获取 * * @author iCode504 * @date 2023-12-21 */ public class ArrayLength { public static void main(String[] args) { int[] array = {1, 3, 5, 7, 9, 11, 13}; System.out.println("array.length = " + array.length); // 空数组的长度 int[] array1 = new int[0]; System.out.println("array1.length = " + array1.length); int[] array2 = {}; System.out.println("array2.length = " + array2.length); // 数组长度必须要>=0,如果定义的数组默认长度是负数的话会抛出NegativeArraySizeException异常 int[] array3 = new int[-1]; System.out.println("array3.length = " + array3.length); } }
运行结果:
四、访问数组元素
通过数组名[索引值]可以访问到这个索引值下的值,其中索引值必须是整数并且处于[0, 数组的长度值)范围内,如果超出这个范围,系统就会抛出数组索引越界异常ArrayIndexOutOfBoundsException
。
/** * 数组元素的访问 * * @author iCode504 * @date 2023-12-21 */ public class ArrayElementsAccess { public static void main(String[] args) { int[] array = {1, 3, 5, 7, 9, 11, 13}; System.out.println("数组的长度是: " + array.length); System.out.println("array[0] = " + array[0]); System.out.println("array[3] = " + array[3]); System.out.println("array[6] = " + array[6]); // 超出[0, array.length)的范围会抛出异常 System.out.println("array[7] = " + array[7]); } }
运行结果:
从运行结果不难看出,数组索引的范围是[0, 6]
,一旦索引值超出这个范围,Java会为我们抛出一个数组索引值越界异常(ArrayIndexOutOfBoundsException
),这种情况在以后编写代码的过程中要尽量避免。
当我们能获取到数组元素的值时,我们就可以修改数组中的元素了。
我们还是以上面的数组为例,我想修改索引值为2的元素值为88,索引值为5的元素值为66:
/** * 数组元素的修改 * * @author iCode504 * @date 2024-01-17 */ public class ArrayElementsModification { public static void main(String[] args) { int[] array = {1, 3, 5, 7, 9, 11, 13}; System.out.println("修改前各个元素的值: "); System.out.println("array[0] = " + array[0]); System.out.println("array[1] = " + array[1]); System.out.println("array[2] = " + array[2]); System.out.println("array[3] = " + array[3]); System.out.println("array[4] = " + array[4]); System.out.println("array[5] = " + array[5]); System.out.println("array[6] = " + array[6]); // 修改索引值为2的元素为88,索引值为3的元素为66 array[2] = 88; array[3] = 66; System.out.println("--------------------"); System.out.println("修改后各个元素的值: "); System.out.println("array[0] = " + array[0]); System.out.println("array[1] = " + array[1]); System.out.println("array[2] = " + array[2]); System.out.println("array[3] = " + array[3]); System.out.println("array[4] = " + array[4]); System.out.println("array[5] = " + array[5]); System.out.println("array[6] = " + array[6]); } }
运行结果符合预期:
五、数组的特点
上边讲了这么多数组的用法,这一部分我们就来简单总结以下数组的特点。其实这一部分我本来想放到前面来讲,但是后来一想放到前面容易给初学者说的云里雾里,于是将数组的特点放到这一部分。数组一共有如下几个特点:
1. 相同数据类型: 所有数组元素必须是相同的数据类型,可以是基本数据类型(如整数、浮点数等)或引用数据类型(如对象、字符串等)。
例如:假设有一个长度为5的int
数组,不管是静态初始化还是动态初始化,里面存储的都是int
类型的值。
/** * 数组特点1:所有数组元素都是相同类型 * * @author iCode504 * @date 2024-01-13 */ public class ArrayCharacteristic1 { public static void main(String[] args) { // 定义一个int类型的数组 int[] array = new int[5]; // 错误写法,因为int[]数组所有元素必须是int类型。 // 而long和double本身就比int范围大,不能直接赋值给数组元素。 // 如需赋值,就需要进行强制类型转换(但是这个过程中也可能会出现一些问题) long number1 = 8; // array[2] = number1; double number2 = 20.34; // array[3] = number2; // int[] array2 = {1, 2, 3, 4, 8.88}; // 正确写法,因为character1赋值给array[4]时,会将值自动类型提升为int类型 // byte、short也同理 char character1 = 'i'; array[4] = character1; byte number3 = 30; array[4] = number3; short number4 = 40; array[4] = number4; } }
2. 固定大小:数组在创建时需要指定固定的大小,这个大小通常在数组声明时确定,且无法在运行时改变。这意味着数组的长度是固定的,无法动态调整。
我们可以使用反证法对上述内容进行证明,假设数组定义了以后,可以动态调整。通过这个假设,我们来编写一段代码证明一下上述假设是否可行:
/** * 数组特点2--创建数组后,无法动态调整数组长度 * * @author iCode504 * @date 2024-01-13 */ public class ArrayCharacteristic2 { public static void main(String[] args) { // 定义一个长度为5的数组 int[] array = new int[5]; System.out.println("数组初始长度: " + array.length); // 如果数组长度可以动态调整,那么我在数组范围外再给数组元素赋值,此时数组长度会动态调整到这个范围外的索引值 array[5] = 20; System.out.println("给数组范围外元素赋值后的长度: " + array.length); } }
在这个程序中,我们尝试将一个元素添加到数组的第六个位置(索引为5),而此时抛出了ArrayIndexOutOfBoundsException
(数组越界异常)。很显然,上述假设并不成立。
尝试访问超出数组长度的索引会导致程序异常。
3. 连续内存空间: 数组的元素在内存中是连续存储的,这也是通过索引直接访问数组元素的原因。
4. 索引访问: 数组中的每个元素都有一个唯一的索引,通过该索引可以访问或修改对应位置的元素。数组的索引从0开始。
这一点我们在第四部分数组元素的访问已经提到,创建指定长度的数组时,会为每一个数组元素分配一个索引值(从0到arr.length - 1
且都是整数)。要想访问到数组元素值,必须通过数组名[索引值]
访问每一个数组元素。
六、遍历数组
使用循环来遍历数组可以获取到数组的每一个元素。遍历数组有两种方式:普通循环遍历和foreach
循环(也称作增强for循环)遍历。
6.1 普通循环遍历
我们可以使用数组的索引值,通过循环来遍历数组,这里我使用普通的for
循环来遍历一个String
类型的数组(当然,使用while
和do-while
循环也OK):
/** * 普通循环遍历数组 * * @author iCode504 * @date 2023-12-21 */ public class ForArray { public static void main(String[] args) { String[] array = {"刘备", "关羽", "张飞", "诸葛亮", "赵云"}; // 遍历范围:[0, array.length) for (int i = 0; i < array.length; i++) { // 用数组名和索引值访问到这个元素的值 System.out.println(array[i]); } } }
运行结果:
在IDEA中,我们可以使用数组名.fori
快速生成一个for
循环:
同理,如果想逆序输出数组,可以使用数组名.forr
:
6.2 foreach循环遍历
foreach
循环是JDK 5的新特性,它也是一种循环结构,这个循环主要用于遍历数组和集合(集合后续会学习到),也称作增强for
循环。
说明:在JDK 8中,在迭代器
Iterator
接口添加了默认方法foreach()
专门用来遍历集合,后续会在集合部分讲到。
foreach
循环的语法结构如下所示:
for (数据类型 变量名 : 数组/集合名) { // 执行代码... }
在这个语法结构中,如果我们使用的是数组arr
,那么结构中的变量名就相当于数组中每一个元素对应的变量名称,即arr[i]
。
例如:假设要使用foreach
循环遍历一个String
类型的数组,使用方式和普通循环遍历语法要简单一些。
/** * foreach循环遍历数组 * * @author iCode504 * @date 2023-12-21 */ public class ForeachArray { public static void main(String[] args) { String[] array = {"刘备", "关羽", "张飞", "诸葛亮", "赵云"}; // foreach循环遍历数组 for (String s : array) { System.out.println(s); } } }
运行结果:
在IDEA中也为我们设置了快捷生成foreach
循环的快捷键数组名.for
,就能快速生成一个foreach
循环:
七、数组元素的默认值
整数类型(byte
、short
、int
、long
)的数组初始化时,每一个数组元素的默认值是0。
/** * 基本数据类型--整数类型数组元素的默认值 * * @author iCode504 * @date 2023-12-21 */ public class ArrayElementsDefaultValue1 { public static void main(String[] args) { // 基本数据类型--byte类型数组元素的默认值 byte[] byteArray = new byte[5]; System.out.println("byte[]元素的默认值是: "); for (byte b : byteArray) { System.out.print(b + "\t"); } System.out.println(); // 基本数据类型--short类型数组元素的默认值 short[] shortArray = new short[5]; System.out.println("short[]元素的默认值是: "); for (short s : shortArray) { System.out.print(s + "\t"); } System.out.println(); // 基本数据类型--int类型数组元素的默认值 int[] intArray = new int[5]; System.out.println("int[]元素的默认值是: "); for (int i : intArray) { System.out.print(i + "\t"); } System.out.println(); // 基本数据类型--long类型数组元素的默认值 long[] longArray = new long[5]; System.out.println("long[]元素的默认值是: "); for (long l : longArray) { System.out.print(l + "\t"); } System.out.println(); } }
运行结果:
浮点类型(float
、double
)的数组初始化,每一个数组元素的默认值是0.0。
/** * 基本数据类型--浮点类型数组元素的默认值 * * @author iCode504 * @date 2023-12-21 */ public class ArrayElementsDefaultValue2 { public static void main(String[] args) { // 基本数据类型--float类型数组元素的默认值 float[] floatArray = new float[5]; System.out.println("float[]元素的默认值是: "); for (float f : floatArray) { System.out.print(f + "\t"); } System.out.println(); // 基本数据类型--double类型数组元素的默认值 double[] doubleArray = new double[5]; System.out.println("double[]元素的默认值是: "); for (double d : doubleArray) { System.out.print(d + "\t"); } System.out.println(); } }
字符类型(char
)的数组初始化时,每一个数组元素的默认值是\u0000
(即Unicode字符表的第一个字符)。
布尔类型(boolean
)的数组初始化时,每一个数组元素的默认值是false
。
/** * 基本数据类型--字符类型和布尔类型数组的默认值 * * @author iCode504 * @date 2023-12-21 */ public class ArrayElementsDefaultValue3 { public static void main(String[] args) { char[] charArray = new char[5]; System.out.println("char[]元素的默认值是: "); for (char c : charArray) { // 间接验证每一个char数组元素默认值是否是Unicode字符表的第一个元素 System.out.print((c == 0) + "\t"); // 写成下面的形式验证也OK // System.out.print((c == '\u0000') + "\t"); } System.out.println(); // 基本数据类型--boolean类型数组元素的默认值 boolean[] booleanArray = new boolean[5]; System.out.println("boolean[]元素的默认值是: "); for (boolean b : booleanArray) { System.out.print(b + "\t"); } System.out.println(); } }
运行结果:
引用数据类型的数组初始化时,每一个数组元素的默认值是null
。
import java.util.Random; /** * 引用数据类型数组的默认值 * * @author iCode504 * @date 2023-12-21 */ public class ArrayElementsDefaultValue4 { public static void main(String[] args) { // 引用数据类型数组元素的默认值 String[] strArray = new String[5]; System.out.println("String[]元素的默认值是: "); for (String s : strArray) { System.out.print(s + "\t"); } System.out.println(); Random[] randomArray = new Random[5]; System.out.println("Random[]元素的默认值是: "); for (Random random : randomArray) { System.out.print(random + "\t"); } } }
运行结果:
八、知识点总结
数组的概念与一维数组知识点总结如下图所示:
如需高清大图,请点击右侧链接下载:点我下载