一、数组概述
1.1 为什么需要数组
如果说现在要求你定义100个整型变量,那么如果按照之前的做法,可能现在定义的的结构如下:
int i1, i2, i3, ... i100;
但是这个时候如果按照此类方式定义就会非常麻烦,因为这些变量彼此之间没有任何的关联,也就是说如果现在突然再有一个要求,要求你输出这100个变量的内容,意味着你要编写System.out.println()语句100次。
如何解决这个问题,Java语言提供了数组(Array)的数据结构,是一个容器可以存储相同数据类型的元素,可以将100个数存储到数组中。
1.2 深入理解数组概念
数组概述:
数组(Array),是多个相同类型数据按一定顺序排列的集合,并使用一个名字命名,并通过编号的方式对这些数据进行统一管理。
数组相关概念:
数组名:数组的名称,用于区分不同的数组,数组只有一个名称,即标识符,要符合标识符规范。
元素类型:数组要存储的元素的数据类型。
数组元素:向数组中存放的数据/元素。
元素下标:对数组元素进行编号,元素下标标明了元素在数组中的位置,从0开始;数组中的每个元素都可以通过下标来访问。
数组长度:数组长度固定不变,避免数组越界。
数组的特点:
数组是有序排列的集合。
数组本身是引用数据类型,而数组中的元素可以是任何数据类型,包括基本数据类型和引用数据类型。
数组的元素的类型,必须一样。
创建数组对象会在内存中开辟一整块连续的空间,而数组名中引用的是这块连续空间的首地址。
数组的长度是固定的,长度一旦确定,就不能修改。
我们可以直接通过下标(或索引)的方式调用指定位置的元素,速度很快。
数组的分类:
按照维数:一维数组、二维数组、三维数组、...
注: 从二维数组开始,我们都称之为多维数组。
按照数组元素的类型:基本数据类型元素的数组、引用数据类型元素的数组(即对象数组)。
二、一维数组的使用
2.1 一维数组的声明和初始化
声明数组的语法格式1:
元素类型[] 数组名 = new 元素类型[元素个数或数组长度];
声明数组的语法格式2:
元素类型[] 数组名 = new 元素类型[]{元素,元素,……};
声明一个变量就是在内存空间划出一块合适的空间,声明一个数组就是在内存空间划出一串连续的空间。
注:
[]在元素类型后 或 数组名后都可以。
Java语言中声明数组时不能指定其长度(数组中元素的数), 例如: int a[5]; //非法
数组初始化分类:
动态初始化:数组声明且为数组元素分配空间与赋值的操作分开进行
int[] arr = new int[3];
arr[0] = 3;
arr[1] = 9;
arr[2] = 8
静态初始化:在定义数组的同时就为数组元素分配空间并赋值。
int arr[] = new int[]{ 3, 9, 8}; 或 int[] arr = {3,9,8};
new关键字:
Java中使用关键字new来创建数组。
定义并用运算符new为之分配空间后,才可以引用数组中的每个元素;
示例代码:
// 变量声明
int num;
// 变量初始化
num = 10;
// 变量声明 + 初始化
int id = 1001;
// 数组声明
int[] ids;
// 静态初始化:数组的初始化和数组元素的赋值操作同时进行
ids = new int[]{1001,1002,1003,1004};
// 动态初始化:数组的初始化和数组元素的赋值操作分开进行
String[] names = new String[5];
// 错误的写法:
// int[] arr1 = new int[];
// int[5] arr2 = new int[5];
// int[] arr3 = new int[3]{1,2,3};
//也是正确的写法:
int[] arr4 = {1,2,3,4,5};// 类型推断
// 总结:数组一旦初始化完成,其长度就确定了。
2.2 一维数组的使用
数组元素的引用方式:数组名[数组元素下标],如boy[0],boy[1]等。
数组元素下标可以是整型常量或整型表达式。如a[3] , b[i] , c[6*i];
数组元素下标从0开始;长度为n的数组合法下标取值范围: 0 —>n-1;如int a[]=new int[3]; 可引用的数组元素为a[0]、a[1]、a[2]
需要注意的是索引从0开始,到数组的长度-1结束。
示例代码:
// 创建一个长度为5的数组,用来存储学生的姓名
String[] names = new String[5];
// 给数组的指定位置赋值
names[0] = "张三";
names[1] = "李四";
names[2] = "王五";
names[3] = "马六";
names[4] = "田七";
// 数组长度5,下标从0开始,到4结束,使用下标5会抛出异常。
// names[5] = "钱八";
// 调用数组的指定位置的元素
System.out.println("下标2的学生的姓名是:"+names[2]);
2.3 获取数组的长度
每个数组都有一个属性length指明它的长度,例如:a.length 指明数组a的长度(元素个数)。
数组一旦初始化,其长度是不可变的。
示例代码:
int[] ids = new int[]{1001,1002,1003,1004};
String[] names = new String[5];
System.out.println(names.length);// 5
System.out.println(ids.length);// 4
2.4 一维数组的遍历
通过for循环,结合下标索引实现数组的遍历。
示例代码:
String[] names = {"张三","李四","王五","马六","田七"};
/*System.out.println(names[0]);
System.out.println(names[1]);
System.out.println(names[2]);
System.out.println(names[3]);
System.out.println(names[4]);*/
for(int i = 0;i < names.length;i++){
System.out.println(names[i]);
}
增强for循环:
foreach语句是java5的新特征之一,在遍历数组、集合方面,foreach为开发人员提供了极大的方便。
foreach语句是for语句的特殊简化版本,但是foreach语句并不能完全取代for语句,然而,任何的foreach语句都可以改写为for语句版本。
foreach的语句格式:
for(元素类型 元素变量x : 数组/集合){
引用了x的java语句;
}
String[] names = {"张三","李四","王五","马六","田七"};
for(String name : names){
System.out.println(name);
}
练习题:
对数据进行处理:计算5位学生的平均分
int [ ] score = {60, 80, 90, 70, 85};
double avg;
avg = (score[0] + score[1] + score[2] + score[3] + score[4])/5;
// 上述写法虽说也可以实现,但是如果10个或100个学生呢?
// 通过遍历数组叠加求和,最后除以数组长度得到平均分。
int [ ] score = {60, 80, 90, 70, 85};
int sum = 0;
for(int i = 0; i < score.length; i++){
sum += score[i];
}
double avg = sum / score.length;
2.5 数组元素的默认初始值
数组是引用类型,它的元素相当于类的成员变量,因此数组一经分配空间,其中的每个元素也被按照成员变量同样的方式被隐式初始化。
对于基本数据类型而言,默认初始化值各有不同。
对于引用数据类型而言,默认初始化值为null(注意与0不同!)
数组元素类型 | 元素默认初始值 |
---|---|
byte | 0 |
short | 0 |
int | 0 |
long | 0L |
float | 0.0F |
double | 0.0 |
char | 0 或写为:’\u0000’(表现为空) |
boolean | false |
引用类型 | null |
示例代码:
int[] arr = new int[4];
for(int i = 0;i < arr.length;i++){
System.out.println(arr[i]);
}
System.out.println("------------------------");
short[] arr1 = new short[4];
for(int i = 0;i < arr1.length;i++){
System.out.println(arr1[i]);
}
System.out.println("------------------------");
float[] arr2 = new float[5];
for(int i = 0;i < arr2.length;i++){
System.out.println(arr2[i]);
}
System.out.println("------------------------");
char[] arr3 = new char[4];
for(int i = 0;i < arr3.length;i++){
System.out.println("----" + arr3[i] + "----");
}
if(arr3[0] == 0){
System.out.println("char类型的默认值是0,但是表现为空");
}
System.out.println("------------------------");
boolean[] arr4 = new boolean[5];
System.out.println(arr4[0]);
System.out.println("------------------------");
String[] arr5 = new String[5];
System.out.println(arr5[0]);
if(arr5[0] == null){
System.out.println("引用类型的默认类型是null,不是null字符串!");
}
2.6 一维数组的内存解析
内存的简化结构:
栈(stack):存放基本类型的变量数据、局部变量和对象的引用,但对象本身不存放在栈中。
堆(heap):存放由new创建的对象和数组以及对象的实例变量。
静态存储区(static storage):又叫方法区:包含的都是在整个程序中永远唯一的元素,如class,static变量。
常量存储区(constant storage):常量值通常直接存放在程序代码内部,这样做是安全的,因为它们永远不会被改变。
静态区/静态域(static storage):随着类的加载而加载并初始化,存在于方法区内存中的字节码文件的静态区域中。
内存解析:
地址引用:
数组属于引用型变量,因此两个相同类型的数组且具有相同的引用,它们就有完全相同的元素。
例如,对于int a[] = {1,2,3}, b[ ]= {4,5};数组变量a和b分别存放着引用0x35ce36和0x757aef。
如果使用了下列赋值语句(a和b的类型必须相同)a=b;那么,a中存放的引用和b的相同,这时系统将释放最初分配给数组a的元素,使得a的元素和b的元素相同。
三、多维数组的使用
Java 语言里提供了支持多维数组的语法。
如果说可以把一维数组当成几何中的线性图形,那么二维数组就相当于是一个表格,像Excel中的表格一样。
二维数组本质上是以数组作为数组元素的数组,即“数组的数组”,其实,从数组底层的运行机制来看,其实没有多维数组。
3.1 二维数组的声明和初始化
声明二位数组的语法格式1(动态初始化):int[][] arr = new int[3][2];
定义了名称为arr的二维数组
二维数组中有3个一维数组
每一个一维数组中有2个元素
一维数组的名称分别为arr[0], arr[1], arr[2]
给第一个一维数组1下标位赋值为78写法是:arr[0][1] = 78;
声明二位数组的语法格式1(动态初始化):int[][] arr = new int[3][];
二维数组中有3个一维数组。
每个一维数组都是默认初始化值null (注意:区别于格式1)
可以对这个三个一维数组分别进行初始化
arr[0] = new int[3]; arr[1] = new int[1]; arr[2] = new int[2];
注:
int[][]arr = new int[][3]; //非法
声明二位数组的语法格式3(静态初始化):int[][] arr = new int[][]{{3,8,2},{2,7},{9,0,1,6}};
定义一个名称为arr的二维数组,二维数组中有三个一维数组
每一个一维数组中具体元素也都已初始化
第一个一维数组 arr[0] = {3,8,2};
第二个一维数组 arr[1] = {2,7};
第三个一维数组 arr[2] = {9,0,1,6};
第三个一维数组的长度表示方式:arr[2].length;
注意特殊写法情况:int[] x,y[]; x是一维数组,y是二维数组。
Java中多维数组不必都是规则矩阵形式。
示例代码:
// 二维数组的声明和初始化
int[] arr = new int[]{1,2,3};//一维数组
// 静态初始化
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
// 动态初始化1
String[][] arr2 = new String[3][2];
// 动态初始化2
String[][] arr3 = new String[3][];
// 错误的情况
// String[][] arr4 = new String[][4];
// String[4][3] arr5 = new String[][];
// int[][] arr6 = new int[4][3]{{1,2,3},{4,5},{6,7,8}};
//也是正确的写法:
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
int[] arr5[] = {{1,2,3},{4,5},{6,7,8}};
3.2 二维数组的使用
数组元素的引用方式:数组名[一维数组下标][二维数组下标],如boy[0][1],boy[1][1]等。
需要注意的是索引从0开始,到数组的长度-1结束。
示例代码:
int[][] arr1 = new int[][]{{1,2,3},{4,5},{6,7,8}};
String[][] arr2 = new String[3][2];
String[][] arr3 = new String[3][];
System.out.println(arr1[0][1]);// 2
System.out.println(arr2[1][1]);// null
// 这样调用报错,因为没有给arr3[1]进行赋值操作,出现空指针异常
// System.out.println(arr3[1][0]);
arr3[1] = new String[4];
System.out.println(arr3[1][0]);
3.3 获取数组的长度
示例代码:
int[] arr4[] = new int[][]{{1,2,3},{4,5,9,10},{6,7,8}};
System.out.println(arr4.length);// 3
System.out.println(arr4[0].length);// 3
System.out.println(arr4[1].length);// 4
3.4 二维数组的遍历
规定:二维数组分为外层数组的元素,内层数组的元素
int[][] arr = new int[4][3];
外层元素:arr[0],arr[1]等
内层元素:arr[0][0],arr[1][2]等
System.out.println(arr[0]);//[I@15db9742
System.out.println(arr[0][0]);//0
示例代码:
//声明二维数组并赋值 int arr[][] = {{},{},{}}
int arr[][] = {{1,2,3},{11,12,13,14},{22,33,44,55,66,77},{1}};
// arr 是数组
// arr[i] 还是数组
for(int i = 0;i < arr.length;i++) {
int ewArr[] = arr[i]; //一维数组里面的每个数组
for(int j = 0;j < ewArr.length;j++) {
System.out.print(ewArr[j]+"\t");
}
System.out.println();
}
System.out.println("--------------------------------");
// 增强for循环遍历
for(int ewArr[] :arr) {
for(int x : ewArr) {
System.out.print(x+"\t");
}
System.out.println();
}
3.5 数组元素的默认初始值
针对于初始化方式一:比如:int[][] arr = new int[4][3];
外层元素的初始化值为:地址值
内层元素的初始化值为:与一维数组初始化情况相同
针对于初始化方式二:比如:int[][] arr = new int[4][];
外层元素的初始化值为:null
示例代码:
int[][] arr = new int[4][3];
System.out.println(arr[0]);//[I@15db9742
System.out.println(arr[0][0]);//0
// System.out.println(arr);//[[I@6d06d69c
System.out.println("*****************");
float[][] arr1 = new float[4][3];
System.out.println(arr1[0]);//地址值
System.out.println(arr1[0][0]);//0.0
System.out.println("*****************");
String[][] arr2 = new String[4][2];
System.out.println(arr2[1]);//地址值
System.out.println(arr2[1][1]);//null
System.out.println("*****************");
double[][] arr3 = new double[4][];
System.out.println(arr3[1]);//null
// System.out.println(arr3[1][0]);//报错