在学习数组之前,我们要先学习一下容器的基本知识,容器:是将多个数据存储到一起,每个数据称为该容器的元素。 生活中的容器:水杯,衣柜,教室..
数组概念
数组就是用于存储数据的长度固定的容器,保证多个数据的数据类型要一致。
百度百科中对数组的定义:
所谓数组(array),就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,以便统一管理他们,然后用编号区分他们,这个名字称为数组名,编号称为下标或索引(index)。组成数组的各个变量称为数组的元素(element)。数组中元素的个数称为数组的长度(length)。
特点:
- 可以存储多个数据
- 多个数据的类型必须保持一致
- 数组一旦创建,长度是永远不可以发生改变
- 创建数组时会在内存中开辟一整块连续的空间。
- 存取元素的速度快,因为可以通过[下标],直接定位到任意一个元素。
数组的特性
- 数组是多个相同类型数据的组合,实现对这些数据的统一管理
- 数组中的元素可以是任何数据类型,包括基本类型和引用类型
- 数组属引用类型,数组型数据是对象(object),数组中的每个元素相当于该对象的成员变量
数组的声明与初始化
- 数组的声明方式一:元素的数据类型[ ] 一维数组的名称;
- 数组的声明方式二:元素的数据类型 一维数组名[ ];
代码示例
public class Demo {
public static void main(String[] args) {
//(1)定义一个存储int类型数组的变量arrayA
int[] arrayA;
//(2)定义一个存储double类型数组的变量arrayB
double arrayB[];
//(3)定义一个存储char类型数组的变量arrayC
char[] arrayC;
}
}
数组的静态初始化
普通格式:
public class Demo {
public static void main(String[] args) {
//定义存储1,2,3,4,5整数的数组容器。
int[] arr1 = new int[]{1, 2, 3, 4, 5};//正确
int[] arr2;
arr2 = new int[]{1, 2, 3, 4, 5};//正确
// int[] arr = new int[5]{1,2,3,4,5}; 错误的,后面有{}指定元素列表,就不需要在[长度]指定长度。
}
}
省略格式
public class Demo {
public static void main(String[] args) {
int[] arr1 = {1, 2, 3, 4, 5};//正确
int[] arr2;
// arr2 = {1,2,3,4,5};//错误
}
}
数组的动态初始化
格式
数组定义格式详解:
- 数组存储的元素的数据类型: 创建的数组容器可以存储什么数据类型的数据。元素的类型可以是任意的Java的数据类型。例如:int, String, Student等
- [ ] : 表示数组。
- 数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组。
- new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用new创建数组对象。
- [长度]:数组的长度,表示数组容器中可以存储多少个元素。
public class Demo {
public static void main(String[] args) {
//(1)创建一个int类型的数组,可以存储3个int数据,给该数组起个名称叫做arrayA
int[] arrayA = new int[3];
//(2)创建一个double类型的数组,可以存储7个double数据,给该数组起个名称叫做arrayB
double[] arrayB = new double[7];
//(3)创建一个char类型的数组,可以存储5个char数据,给该数组起个名称叫做arrayC
char[] arrayC = new char[5];
}
}
数组的基本使用
数组的访问
- 索引: 每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。
- 索引范围:[0, 数组的长度-1]
- 格式:数组名[索引]
- 为数组中的元素赋值,我们可以使用 :数组名[索引] = 数值
- 获取出数组中的元素,我们可以使用 :变量=数组名[索引]
代码示例
public class Demo {
public static void main(String[] args) {
//定义存储int类型数组,赋值元素1,2,3,4,5
int[] arr = {1, 2, 3, 4, 5};
//为0索引元素赋值为6
arr[0] = 6;
//获取数组0索引上的元素
int i = arr[0];
System.out.println(i);
//直接输出数组0索引元素
System.out.println(arr[0]);
}
}
数组的遍历
- 什么是数组遍历: 就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。
- 数组的长度属性: 每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度,语句为:
数组名.length
,属性length的执行结果是数组的长度,int类型结果。由次可以推断出,数组的最大索引值为数组名.length-1
。
代码示例
public class Demo {
public static void main(String[] args) {
int[] arr = new int[]{1, 2, 3, 4, 5};
//打印数组的属性,输出结果是5
System.out.println("数组的长度:" + arr.length);
//遍历输出数组中的元素
System.out.println("数组的元素有:");
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
数组元素的默认值
当我们使用动态初始化创建数组时,此时只确定了数组的长度,那么数组的元素是什么值呢? 数组的元素有默认值如下图所示:
数组内存图
内存概述
内存是计算机中重要的部件之一,它是与CPU进行沟通的桥梁。其作用是用于暂时存放CPU中的运算数据,以及与硬盘等外部存储器交换的数据。只要计算机在运行中,CPU就会把需要运算的数据调到内存中进行运算,当运算完成后CPU再将结果传送出来。我们编写的程序是存放在硬盘中的,在硬盘中的程序是不会运行的,必须放进内存中才能运行,运行完毕后会清空内存。Java虚拟机要运行程序,必须要对内存进行空间的分配和管理。
Java虚拟机的内存划分
为了提高运算效率,就对空间进行了不同区域的划分,因为每一片区域都有特定的处理数据方式和内存管理方式。
区域详解
查看下面代码
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr);//[I@5f150435
}
分析执行流程
结论:
- 数组名称保存数组在堆内存中的地址值,通过数组名称找到堆内存中的具体数组,然后通过索引编号找到对应的具体的某个元素
- 每个数组都有自己独立的内存空间,互不影响,互不干扰
- 使用数组名进行赋值时,传递的是地址。多个变量指向一个数组的时候,变量都是操作同一个数组
public class Demo {
public static void main(String[] args) {
// 定义数组,存储3个元素
int[] arr = new int[3];
//数组索引进行赋值
arr[0] = 5;
arr[1] = 6;
arr[2] = 7;
//输出1索引上的元素值
System.out.println(arr[1]); //6
//定义数组变量arr2,将arr的地址赋值给arr2
int[] arr2 = arr;
//修改1索引上的值
arr2[1] = 9;
System.out.println(arr[1]);//9
System.out.println(arr2[1]);//9
}
}
数组操作的常见问题
数组越界异常
/*
数组操作的常见问题一:
数组索引越界(超出了范围)异常
1.问题描述: java.lang.ArrayIndexOutOfBoundsException类,数组索引越界异常类
2.产生原因:
使用索引编号范围数组元素时,给出的索引编号不存在(超出了范围)
索引编号范围: 最小值是0,最大值是数组长度 减 1 (one.length - 1)
3.解决方案:
根据控制台的打印信息,找到出现问题的索引,进行修改
*/
public class Demo01ArrayProblem {
public static void main(String[] args) {
//创建int数组array,并初始化
//int[] one = new int[]{100,200,300};
int[] one = {100,200,300};//100的索引编号是0,200的索引编号是1,300的索引编号是2
System.out.println(one);//数组名称one代表数组的内存地址值:[I@1540e19d
System.out.println(one[0]);//100
System.out.println(one[1]);//200
System.out.println(one[2]);//300
//System.out.println(one[5]);//索引5: 不存在,报出数组索引越界异常
}
}
数组空指针异常
/*
数组操作的常见问题二:
空指针异常
1.问题描述: java.lang.NullPointerException类,空指针异常类
2.产生原因:
null是一个引用类型的常量,可以给任意类型引用变量赋值,
当把null赋值给数组变量one之后,数组变量one将不再指向堆内存空间的任何数组,
也就不可以通过one再访问数组元素,只要访问,报出空指针异常
3.解决方案:
(1)不要通过值为null的数组变量,访问数组元素
(2)根据控制台打印的相关异常信息,找到数组变量是null的地方进行修改,
让数组变量指向一个堆内存空间的数组,就可以访问数组元素了
*/
public class Demo02ArrayProblem {
public static void main(String[] args) {
//创建int数组array,并初始化
//int[] one = new int[]{100,200,300};
int[] one = {100,200,300};//100的索引编号是0,200的索引编号是1,300的索引编号是2
System.out.println(one);//数组名称one代表数组的内存地址值:[I@1540e19d
System.out.println(one[0]);//100
System.out.println(one[1]);//200
System.out.println(one[2]);//300
one = null;
System.out.println(one);//null
//System.out.println(one[0]);//错误: 控制针异常
}
}
数组的经典练习题
import java.util.Scanner;
public class Test5Array {
/*
需求:在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值 (不考虑小数部分)。
思路:
1.定义一个数组,用动态初始化完成数组元素的初始化,长度为6
2.键盘录入评委分数
3.由于是6个评委打分,所以,接收评委分数的操作,用循环
4.求出数组最大值
5.求出数组最小值
6.求出数组总和
7.按照计算规则进行计算得到平均分
8.输出平均分
*/
public static void main(String[] args) {
// 1.定义一个数组,用动态初始化完成数组元素的初始化,长度为6
int[] arr = new int[6];
// 2.键盘录入评委分数
Scanner sc = new Scanner(System.in);
// 3.由于是6个评委打分,所以,接收评委分数的操作,用循环
for (int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i+1) + "个评委的打分:");
int score = sc.nextInt();
if(score >= 0 && score <= 100){
// 合法的分值
arr[i] = score;
}else{
// 非法的分值
System.out.println("您的打分输入有误, 请检查是否是0-100之间的");
i--;
}
}
// 4.求出数组最大值
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if(max < arr[i]){
max = arr[i];
}
}
// 5.求出数组最小值
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if(min > arr[i]){
min = arr[i];
}
}
// 6.求出数组总和
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
// 7.按照计算规则进行计算得到平均分
int avg = (sum - max - min ) / 4;
// 8.输出平均分
System.out.println(avg);
}
}
二维数组
二维数组:本质上就是元素为一维数组的一个数组。
int[][] arr; //arr是一个二维数组,可以看成元素是int[]一维数组类型的一个数组
二维数组的声明与初始化
声明的语法格式
静态初始化
如果是静态初始化,右边new 数据类型[ ][ ]中不能写数字,因为行数和列数,由{}的元素个数决定
代码示例
public class Demo {
public static void main(String[] args) {
int[][] arr;
arr = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
//arr = new int[3][3]{{1,2,3},{4,5,6},{7,8,9}};//错误,静态初始化右边new 数据类型[]中不能写数字
int[][] arr1 = new int[][]{{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
int[][] arr2 = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};//声明与初始化必须在一句完成
}
}
动态初始化(规则二维表:每一行的列数是相同的)
代码示例
public class Demo {
public static void main(String[] args) {
//定义一个二维数组
int[][] arr = new int[3][2];
//定义了一个二维数组arr
//这个二维数组有3个一维数组的元素
//每一个一维数组有2个元素
//输出二维数组名称
System.out.println(arr); //地址值 [[I@175078b
//输出二维数组的第一个元素一维数组的名称
System.out.println(arr[0]); //地址值 [I@42552c
System.out.println(arr[1]); //地址值 [I@e5bbd6
System.out.println(arr[2]); //地址值 [I@8ee016
//输出二维数组的元素
System.out.println(arr[0][0]); //0
System.out.println(arr[0][1]); //0
}
}
动态初始化(不规则:每一行的列数可能不一样)
代码示例
public class Demo {
public static void main(String[] args) {
//定义数组
int[][] arr = new int[3][];
System.out.println(arr); //[[I@175078b
// System.out.println(arr[1][0]); NullPointerException
System.out.println(arr[0]); //null
System.out.println(arr[1]); //null
System.out.println(arr[2]); //null
//动态的为每一个一维数组分配空间
arr[0] = new int[2];
arr[1] = new int[3];
arr[2] = new int[1];
System.out.println(arr[0]); //[I@42552c
System.out.println(arr[1]); //[I@e5bbd6
System.out.println(arr[2]); //[I@8ee016
System.out.println(arr[0][0]); //0
System.out.println(arr[0][1]); //0
//ArrayIndexOutOfBoundsException
//System.out.println(arr[0][2]); //错误
arr[1][0] = 100;
arr[1][2] = 200;
}
}
二维数组的相关操作
- 获取二维数组中一维数组的个数: 二维数组名.length
- 获取二维数组中具体的一维数组的地址: 二维数组名[行下标]
- 获取二维数组中具体的一维数组的长度:二维数组名[行下标].length
- 获取某个具体的元素:二维数组名[行下标][列下标]
二维数组遍历
public class Test1 {
/*
需求:
已知一个二维数组 arr = {{11, 22, 33}, {33, 44, 55}};
遍历该数组,取出所有元素并打印
步骤:
1. 遍历二维数组,取出里面每一个一维数组
2. 在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素
*/
public static void main(String[] args) {
int[][] arr = {{11, 22, 33}, {33, 44, 55}};
// 1. 遍历二维数组,取出里面每一个一维数组
for (int i = 0; i < arr.length; i++) {
//System.out.println(arr[i]);
// 2. 在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素
//int[] temp = arr[i];
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
}
二维数组求和
public class Test2 {
/*
需求:
某公司季度和月份统计的数据如下:单位(万元)
第一季度:22,66,44
第二季度:77,33,88
第三季度:25,45,65
第四季度:11,66,99
步骤:
1. 定义求和变量,准备记录最终累加结果
2. 使用二维数组来存储数据,每个季度是一个一维数组,再将4个一维数组装起来
3. 遍历二维数组,获取所有元素,累加求和
4. 输出最终结果
*/
public static void main(String[] args) {
// 1. 定义求和变量,准备记录最终累加结果
int sum = 0;
// 2. 使用二维数组来存储数据,每个季度是一个一维数组,再将4个一维数组装起来
int[][] arr = { {22,66,44} , {77,33,88} , {25,45,65} , {11,66,99}};
// 3. 遍历二维数组,获取所有元素,累加求和
for (int i = 0; i < arr.length; i++) {
for(int j = 0; j < arr[i].length; j++){
sum += arr[i][j];
}
}
// 4. 输出最终结果
System.out.println(sum);
}
}
注意:
二维数组中保存的是一维数组的内存地址值