数组的概述
数组就是用于存储数据的长度固定的容器,保证多个数据的数据类型要一致。容器:是将多个数据存储到一起,每个数据称为该容器的元素。 生活中的容器:水杯,衣柜,教室 百度百科中对数组的定义:所谓数组(array),就是相同数据类型的元素按一定顺序排列的集合,就是把有限个类型相同的变量用一个名字命名,以便统一管理他们,然后用编号区分他们,这个名字称为数组名,编号称为下标或索引(index)。组成数组的各个变量称为数组的元素(element)。数组中元素的个数称为数组的长度(length)。
数组的特点:
- 数组的长度一旦确定就不能修改
- 创建数组时会在内存中开辟一整块连续的空间。
- 存取元素的速度快,因为可以通过[下标],直接定位到任意一个元素。
数组的声明与初始化
数组的声明有下面二种格式:
- 数据类型[ ] 数组名;
- 数据类型 数组名[ ];
代码示例
//(1)定义一个存储int类型数组的变量arrayA
int[] arrayA;
//System.out.println(arrayA);错误的: arrayA只是一个用来存储数组的变量,但是目前没有向arrayA中存储数组
//(2)定义一个存储double类型数组的变量arrayB
double arrayB[];
//System.out.println(arrayB);错误的: arrayB只是一个用来存储数组的变量,但是目前没有向arrayA中存储数组
当我们声明一个变量,而没有给其初始化的时候,是无法使用的。数组同样如此,下面我们就来学习一下数组的初始化方式
方式一 :数组动态初始化
数组动态初始化就是只给定数组的长度,由系统给出默认初始化值
格式:
数组定义格式详解:
- 数组存储的元素的数据类型: 创建的数组容器可以存储什么数据类型的数据。元素的类型可以是任意的Java的数据类型。例如:int, String, Student等
- [ ] : 表示数组。
- 数组名字:为定义的数组起个变量名,满足标识符规范,可以使用名字操作数组。
- =:表示赋值,把具体的=右边new出来的数组容器,存储到=左边的数组变量中,但是存储的是数组在内存空间的地址值
- new:关键字,创建数组使用的关键字。因为数组本身是引用数据类型,所以要用new创建数组对象。
- [长度]:数组的长度,表示数组容器中可以存储多少个元素。
- 注意:数组有定长特性,长度一旦指定,不可更改。和水杯道理相同,买了一个2升的水杯,总容量就是2升,不能多也不能少。
定义可以存储3个整数的数组容器,代码如下:
int[] arr = new int[3];
方式二: 数组静态初始化
静态初始化就是在创建数组时,直接确定数组元素
标准格式:
定义存储1,2,3,4,5整数的数组容器
int[] arr = new int[]{1, 2, 3, 4, 5};
简化格式:
定义存储1,2,3,4,5整数的数组容器
int[] arr = {1, 2, 3, 4, 5};
注意事项:
动态初始化和标准格式的静态初始化,可以分两步完成,简化格式静态初始化,不能分成两步完成。代码示例:
//动态初始化
int[] arr1;
arr1 = new int[3];
//静态初始化,标准格式
int[] arr2;
arr2 = new int[]{1, 2, 3, 4, 5};//正确
//int[] arr = new int[5]{1,2,3,4,5};错误的,后面有{}指定元素列表,就不需要在[长度]指定长度。
int[] arr3;
//arr3 = {1,2,3,4,5};错误,必须在一个语句中完成,不能分开两个语句写
操作中数组元素
直接打印数组名称,输出的是一个十六进制的整数数字,代表数组在内存空间的地址值。我们要访问数组中的元素就必须用到index,索引: 每一个存储到数组的元素,都会自动的拥有一个编号,从0开始,逐一增加,这个自动编号称为数组索引(index),可以通过数组的索引访问到数组中的元素。索引范围:[0, 数组的长度-1]。格式:数组名[索引]
索引访问数组中的元素:
- 数组名[索引] = 数值:为数组中的元素赋值
- 变量 = 数组名[索引]:获取出数组中的元素
代码示例
public class Demo04Array {
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);//6
//直接输出数组0索引元素
System.out.println(arr[0]);//6
}
}
数组的遍历
数组的长度属性: 每个数组都具有长度,而且是固定的,Java中赋予了数组的一个属性,可以获取到数组的长度,语句为:数组名.length,属性length的执行结果是数组的长度,int类型结果。由次可以推断出,数组的最大索引值为数组名.length-1。
数组遍历: 就是将数组中的每个元素分别获取出来,就是遍历。遍历也是数组操作中的基石。
public class Demo05Array {
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 class Demo01ArrayTest {
public static void main(String[] args) {
int[] arr = new int[3];
System.out.println(arr[3]);
}
}
数组长度为3,索引范围是0~2,但是我们却访问了一个3的索引。程序运行后,将会抛出ArrayIndexOutOfBoundsException 数组越界异常。在开发中,数组的越界异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。解决方案:将错误的索引修改为正确的索引范围即可!
空指针异常
观察一下代码,运行后会出现什么结果。
public class Demo02ArrayTest {
public static void main(String[] args) {
int[] arr = new int[3];
//把null赋值给数组
arr = null;
System.out.println(arr[0]);
}
}
arr = null 这行代码,意味着变量arr将不会在保存数组的内存地址,也就不允许再操作数组了,因此运行的时候会抛出 NullPointerException 空指针异常。在开发中,空指针异常是不能出现的,一旦出现了,就必须要修改我们编写的代码。解决方案:给数组一个真正的堆内存空间引用即可
数组练习
数组获取最大值
/*
需求: 从数组 int[] arr = {12,45,98,73,60}中查找最大值
*/
public class Demo03ArrayTest {
public static void main(String[] args) {
int[] arr = {12, 45, 98, 73, 60};
// 1. 假设数组中的第一个元素为最大值
int max = arr[0];
// 2. 遍历数组, 获取每一个元素, 准备进行比较
for (int i = 1; i < arr.length; i++) {
// 3. 如果比较的过程中, 出现了比max更大的, 让max记录更大的值
if (arr[i] > max) {
max = arr[i];
}
}
// 4. 循环结束后, 打印最大值.
System.out.println("max:" + max);
}
}
数组基本查找
package demo02;
import java.util.Scanner;
/*
需求:
已知一个数组 arr = {19, 28, 37, 46, 50}; 键盘录入一个数据,查找该数据在数组中的索引,并在控
制台输出找到的索引值。
*/
public class Demo04ArrayTest {
public static void main(String[] args) {
// 1.定义一个数组,用静态初始化完成数组元素的初始化
int[] arr = {19, 28, 37, 46, 50};
// 2.键盘录入要查找的数据,用一个变量接收
Scanner sc = new Scanner(System.in);
System.out.println("请输入您要查找的元素:");
int num = sc.nextInt();
// 3.定义一个索引变量,初始值为-1
// 假设要查找的数据, 在数组中就是不存在的
int index = -1;
// 4.遍历数组,获取到数组中的每一个元素
for (int i = 0; i < arr.length; i++) {
// 5.拿键盘录入的数据和数组中的每一个元素进行比较,如果值相同,就把该值对应的索引赋值给索引变量,并结束循环
if(num == arr[i]){
// 如果值相同,就把该值对应的索引赋值给索引变量,并结束循环
index = i;
break;
}
}
// 6.输出索引变量
System.out.println(index);
}
}
评委打分
import java.util.Scanner;
/*
需求:在编程竞赛中,有6个评委为参赛的选手打分,分数为0-100的整数分。
选手的最后得分为:去掉一个最高分和一个最低分后 的4个评委平均值 (不考虑小数部分)。
*/
public class Demo05ArrayTest {
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);
}
}
二维数组
概述 : 二维数组也是一种容器,不同于一维数组,该容器存储的都是一维数组容器。本质上就是元素为一维数组的一个数组。 二维数组存储一维数组的时候,存储的是一维数组的内存地址。二维数组中存储的是一维数组, 能存入 提前创建好的一维数组。
动态初始化格式:
代码示例
public class Demo {
public static void main(String[] args) {
// 数据类型[][] 变量名 = new 数据类型[m][n];
int[][] arr = new int[3][3];
/*
[[I@10f87f48
@ : 分隔符
10f87f48 : 十六进制内存地址
I : 数组中存储的数据类型
[[ : 几个中括号就代表的是几维数组
*/
System.out.println(arr);//[[I@4554617c
/*
二维数组存储一维数组的时候, 存储的是一维数组的内存地址
*/
System.out.println(arr[0]); //[I@74a14482
System.out.println(arr[0][0]);//0
// 向二维数组中存储元素
arr[0][0] = 11;
arr[2][2] = 33;
// 从二维数组中取出元素并打印
System.out.println(arr[0][0]);//11
System.out.println(arr[0][1]);//0
System.out.println(arr[2][2]);//33
}
}
二维数组静态初始化
代码示例
public class Demo {
/*
完整格式:数据类型[][] 变量名 = new 数据类型[][]{ {元素1, 元素2...} , {元素1, 元素2...} ...};
简化格式: 数据类型[][] 变量名 = { {元素1, 元素2...} , {元素1, 元素2...} ...};
*/
public static void main(String[] args) {
int[] arr1 = {11,22,33};
int[] arr2 = {44,55,66};
int[][] arr = {{11,22,33}, {44,55,66}};
System.out.println(arr[0][2]);
int[][] array = {arr1,arr2};
System.out.println(array[0][2]);
}
}
二维数组中的相关操作
- 获取二维数组中一维数组的个数:二维数组名.length
- 获取二维数组中指定的一维数组:二维数组名[行下标],行下标的范围:[0, 二维数组名.length-1]
- 获取二维数组中指定一维数组中元素的个数:二维数组名[行下标].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. 在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素
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);
}
}
元素打乱
import java.util.Random;
/*
需求:已知二维数组 arr = {{1,2,3},{4,5,6},{7,8,9}};用程序实现把数组中的元素打乱,并在控制台输出打乱后的数组元素
*/
public class ArrayTest02 {
public static void main(String[] args) {
//定义二维数组,并进行静态初始化
int[][] arr = {{1, 2, 3}, {4, 5, 6}, {7, 8, 9}};
//创建随机数对象
Random r = new Random();
//遍历二维数组,进行元素打乱
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
//arr[i][j]
int x = r.nextInt(arr.length);
int y = r.nextInt(arr[x].length);
//元素交换
int temp = arr[i][j];
arr[i][j] = arr[x][y];
arr[x][y] = temp;
}
}
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.print(arr[i][j] + " ");
}
System.out.println();
}
}
}