数组的概念
数组是一种用于存储数据的方式,使用一组连续的存储空间来存储多个相同数据类型的值,也就是说,数组是同一种类型数据的集合。
特点:类型相同,长度固定,数组中的元素从0开始编号。
数组的定义
-
数组的创建:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
eg:
int[] arr = new int[3]
,定义一个数据类型为int
、名称为arr
的数组。 -
关键字
new
:用来在内存中产生一个容器实体,数据要存储是需要有空间的,存储很多数据的空间用new 操作符来开辟。
arr
是属于什么数据类型?
-
任何一个变量都得有自己的数据类型;注意这个
arr
不是int
类型的,int
代表的是容器里边元素的类型;arr
是数组类型的,数组是一种单独的数据类型。数据类型分为基本数据类型和引用数据类型,数组是三种引用数据类型之一。
int[] arr = new int[5];
在内存中发生了什么?
- 内存任何一个程序,运行的时候都需要在内存中开辟空间。
int[] arr = new int[5];
涉及java虚拟机在执行程序时所开辟的空间。
定义数组主要有两种格式:
-
格式一
// 元素类型[] 数组名 = new 元素类型[元素个数或数组长度]; int[] arr1 = new int[5]; float[] arr2 = new float[5];
-
格式二
// 元素类型[] 数组名 = new 元素类型[]{元素,元素,……}; int[] arr1 = new int[]{3,5,1,7}; float[] arr2 = {1.3,1.5,1.1,1.7};
- 给数组分配空间时,必须指定数组能够存储的元素个数来确定数组大小;
- 创建数组之后不能修改数组的大小;
- 可以使用length 属性获取数组的大小。
数组的初始化
-
数组的声明与赋值
int[] arr = new int[2]; a[0] = 10; a[1] = 20;
-
直接明确数组的长度以及数组中元素的内容
int[] arr = new int[]{20,30,40}; int[] arr = {20,30,40};
-
数组初始化必须使用运算符new,否则会报错
int[] arr; //错误,缺少new arr = {20,30,40};
-
初始化数组,必须将声明、创建、初始化都放在一条语句中个,分开会产生语法错误。
数组下标的有效范围与常见异常
-
ArrayIndexOutOfBoundsException
索引值越界异常
-
对于一个数组来见,有效的下标范围是0 ~ 数组长度-1,一旦访问了不在有效范围的下标,那么就会产生数组下标越界异常。
-
NullPointerException
空指针异常:引用类型变量没有指向任何对象,而访问了对象的属性或者是调用了对象的方法。
数组内存分析
-
栈内存:栈内存存储的都是局部变量,变量一旦出了自己的作用域,那么就会马上从内存的消失,释放内存空间;
-
堆内存:堆内存存储的都是对象内存,对象一旦被使用完,并不会马上从内存中消失,而是等待垃圾回收器不定时的把垃圾对象回收,这时候该对象才会消失,释放内存;
-
凡是以new关键字创建的对象,JVM都会在堆内存中开辟一个新的空间,创建一个新的对象;
-
对象如果没有变量引用了,那么该对象就是一个垃圾对象了。
双数组的内存分析
public class Test2 {
public static void main(String[] args) {
int[] arr1 = new int[2];
int[] arr2 = new int[3];
System.out.println(arr1);
System.out.println(arr1[0]); // 0
System.out.println(arr1[1]); // 0
System.out.println(arr2);
System.out.println(arr2[0]);
System.out.println(arr2[1]);
System.out.println(arr2[2]);
arr1[0] = 100;
arr2[0] = 200;
System.out.println("-----------");
System.out.println(arr1);
System.out.println(arr1[0]); // 100
System.out.println(arr1[1]); // 0
System.out.println(arr2);
System.out.println(arr2[0]);
System.out.println(arr2[1]);
System.out.println(arr2[2]);
}
}
二维数组
在计算机中,二维表结构使用二维数组来表示。
创建二维数组
二维数组可以看作是特殊的一维数组,它有两种声明方式:
// 数组元素类型 数组名字[][];
// 数组元素类型[][] 数组名字;
int arr1[][];
char[][] arr2;
同一维数组一样,二维数组在声明时也没有分配内存空间,同样要使用关键字new来分配内存,然后才可以访问每个元素。 为二维数组分配内存有两种方式∶
int a[][];
a = new int[2][4]; //直接分配行类
int b[][];
b = new int[2][]; //先分配行,再分配列
b[0] = new int[2]; //给第一行分配列
b[1] = new int[2]; //给第二行分配列
创建二维数组的时候,可以只声明"行"的长度,而不声明"列"的长度,如∶
int a[][] = new int[2][]; //可省略列的长度// 如果不声明"行"数量的话,就是错误的写法// 错误写法!int b[][] = new int[][];// 错误写法!int c[][] = new int[][2];
二维数组的赋值
-
二维数组的初始化方法与一维数组类似,也有3种方式;
public class InitTDArray { public static void main(String[] args) { /* 第一种方式 */ int tdarr1[][] = { { 1, 3, 5 }, { 5, 9, 10 } }; /* 第二种方式 */ int tdarr2[][] = new int[][] { { 65, 55, 12 }, { 92, 7, 22 } }; /* 第三种方式 */ int tdarr3[][] = new int[2][3]; // 先给数组分配内存空间 tdarr3[0] = new int[] { 6, 54, 71 }; // 给第一行分配一个一维数组 tdarr3[1][0] = 63; // 给第二行第一列赋值为63 tdarr3[1][1] = 10; // 给第二行第二列赋值为10 tdarr3[1][2] = 7; // 给第二行第三列赋值为7 }}
-
二维数组有两个索引(即下标),构成由行和列组成的一个矩阵。
多维数组
比一维数组维数高的叫多维数组,理论上二维数组也属于多维数组。
int a[][][] = new int[3][4][5]; //创建三维数组char b[][][][] = new char[6][7][8][9]; //创建四维数纹double c[][][][][]= new double[10][11][12][13][14]; // 创建五维数组
注意: 多维数组在Java中是可以使用的,但因为其结构关系太过于复杂,容易出错,所以不推荐在程序中使用比二维数组更高维数的数组;如果需要存储复杂的数据,推荐使用集合类或自定义类集合类包括List、Map等。
不规则数组
Java支持不规则的数组,例如二维数组中,不同行的元素个数可以不同∶
a[][] = new int[3][]; // 创建二维数组,指定行数,不指定列数a[0]= new int[5];// 第一行分配5个元素a[1] = new int[3];// 第二行分配3个元素a[2] = new int[4];// 第三行分配4个元素
这个不规则二维数组所占的空间如下图所示:
创建IrregularArrax
类,声明一个不规则二维数组,输出数组每行的元素个数及各元素的值,代码如下∶
public class IrregularArray {
public static void main(String[] args) {
int a[][] = new int[3][]; // 创建二维数组,指定行数,不指定列数
a[0] = new int[] { 52, 64, 85, 12, 3, 64 }; // 第一行分配5个元素
a[1] = new int[] { 41, 99, 2 }; // 第二行分配3个元素
a[2] = new int[] { 285, 61, 278, 2 }; // 第三行分配4个元素
for (int i = 0; i < a.length; i++) {
System.out.print("a[" + i + "]中有" + a[i].length + "个元素,分别是:");
for (int tmp : a[i]) { // foreach循环输出数字中元素
System.out.print(tmp + " ");
}
System.out.println();
}
}
}
foreach
循环语句是 Java 1.5 的新特征之一,在遍历数组、集合方面,为开发者提供了极大的方便。foreach
循环语句是 for 语句的特殊简化版本,主要用于执行遍历功能的循环。for(类型 变量名:集合) { //每执行一次循环语句,循环变量就读取集合中的一个元素 语句块; } // “类型”为集合元素的类型 // “变量名”表示集合中的每一个元素 // “集合”是被遍历的集合对象或数组
数组的基本操作
数组遍历
- 遍历二维数组需使用双层
for
循环,通过数组的length
属性可获得数组的长度。 - 如果有一个二维数组
a[][]
,a.length
返回的是数组的行数,a[n].length
返回的是第n+1行的列数量。
使用二维数组实现杨辉三角算法
public class YangHui {// 杨辉三角算法的实现
public static void main(String[] args) {
// 定义一个长度为10的二维数组
int[][] Array_int = new int[10][];
// 向数组中记录杨辉三角形的值
for (int i = 0; i < Array_int.length; i++) {// 遍历行数
Array_int[i] = new int[i + 1];// 定义二维数组的列数
// 遍历二维数组的列数
for (int j = 0; j < Array_int[i].length; j++) {
if (i <= 1) {// 如果是数组的前两行
Array_int[i][j] = 1;// 将其设置为1
continue;
} else {
// 如果是行首或行尾
if (j == 0 | j == Array_int[i].length - 1)
Array_int[i][j] = 1;// 将其设置为1
else// 根据杨辉算法进行计算
Array_int[i][j] = Array_int[i - 1][j - 1] + Array_int[i - 1][j];
}
}
}
for (int i = 0; i < Array_int.length; i++) {// 输出杨辉三角
for (int j = 0; j < Array_int[i].length; j++)
System.out.print(Array_int[i][j] + "\t");
System.out.println();
}
}
}
运行结果如下:
填充和替换数组元素
数组中的元素定义完成后,可通过Arrays
类的静态方法fill()
方法来对数组中的元素进行分配,起到填充和替换的效果。fill()
方法可将指定的整数值分配给int
型数组的每个元素。
语法为Arrays.fill(int[] a, int value)
。
创建 Swap类,通过fill()方法填充数组元素,最后将数组中的各个元素输出,代码如下∶
import java.util.Arrays; //导入java.util.Arrays类
public class Swap {
public static void main(String[] args) {
int arr[] = new int[5]; // 创建int型数组
Arrays.fill(arr, 8); // 使用同一个值对数组进行填充,{8,8,8,8,8}
for (int i = 0; i < arr.length; i++) { // 循环遍历数组中的元素
// 将数组中的元素依次输出
System.out.println("第" + i + "个元素是:" + arr[i]);
}
}
}
Arrays 类是一个工具类,其中包含了数组操作的很多方法。这个 Arrays 类里均为 static 修饰的方法(static 修饰的方法可以直接通过类名调用),可以直接通过
Arrays.xxx(xxx)
的形式调用方法。Arrays类的其他数组操作方法:
int binarySearch(type[] a, type key)
:使用二分法查询key
元素值在a
数组中出现的索引,如果a
数组不包含key
元素值,则返回负数。调用该方法时要求数组中元素己经按升序排列,这样才能得到正确结果。int binarySearch(type[] a, int fromIndex, int toIndex, type key)
:与前一个方法类似,但它只搜索a
数组中fromIndex
到toIndex
索引的元素。type[] copyOf(type[] original, int length)
:把original
数组复制成一个新数组,其中length
是新数组的长度。如果length
小于original
数组的长度,则新数组就是原数组的前面length
个元素,如果length
大于original
数组的长度,则新数组的前面元索就是原数组的所有元素,后面补充0
(数值类型)、false
(布尔类型)或者null
(引用类型)。type[] copyOfRange(type[] original, int from, int to):
与前面方法相似,但这个方法只复制original
数组的from
索引到to
索引的元素。boolean equals(type[] a, type[] a2):
如果a
数组和a2
数组的长度相等,而且a
数组和a2
数组的数组元素也一一相同,该方法将返回true
。void fill(type[] a, int fromIndex, int toIndex, type val):
将a
数组的fromIndex
到toIndex
索引的数组元素赋值为val
。void sort(type[] a):
对a
数组的数组元素进行排序。void sort(type[] a, int fromIndex, int toIndex)
:与前一个方法相似,区别是该方法仅仅对fromIndex
到toIndex
索引的元素进行排序。String toString(type[] a)
:将一个数组转换成一个字符串,按顺序把多个数组元素连缀在一起,多个数组元素使用英文逗号’,‘和空格’ '隔开。