文章目录
- Java 数组
- 一、数组介绍
- 二、数组
- 1. 数组静态初始化
- 1.1 数组定义格式
- 1.2 数组静态初始化
- 2. 数组元素访问
- 3. 数组遍历操作
- 3.1 数组遍历介绍
- 3.2 数组遍历场景
- 3.3 数组遍历案例
- 1)数组遍历-求偶数和
- 2)数组遍历-求最大值
- 3)数组遍历综合案例
- 4. 数组动态初始化
- 4.1 数组动态初始化介绍
- 4.2 两种初始化的区别
- 4.3 数组动态初始化案例
- 1)使用键盘录入填充数组
- 2)使用随机数填充数组
- 5. 数组内存图
- 5.1 Java 内存分配介绍
- 5.2 方法的参数传递问题
- 6. 数组常见问题
- 6.1 索引越界异常
- 6.2 空指针异常
- 三、二维数组
- 1. 二维数组介绍
- 2. 二维数组静态初始化
- 2.1 二维数组静态初始化格式
- 2.2 二维数组元素访问
- 3. 二维数组遍历
- 4. 二维数组动态初始化
Java 数组
一、数组介绍
数组指的是一种容器,可以用来存储同种数据类型的多个值。
那么为什么要使用数组呢?
在销售部门中,如果我们想要对部门中销售情况进行分析,我们凭借基本数据类型中的 int 类型也可以实现,但是人数多的话,就需要创建多个变量,但这样感觉特别复杂,光是想变量名就感觉头疼,但如果使用数组,我们可以把数据通过简短的代码对数据进行存储。
使用思路
今后若要操作的多数据,属于同一组数据就可以考虑使用数组容器进行维护
二、数组
1. 数组静态初始化
1.1 数组定义格式
- 格式一:数据类型[ ] 数组名
- 范例:int[ ] array
- 格式二:数据类型 数组名[ ]
- 范例:int array[ ]
下面我们通过一个案例来学习数组的定义格式:
package cn.edu.hgu.array;
public class ArrayDemo1 {
public static void main(String[] args) {
int[] arr1;
int arr2[];
}
}
注意:这种定义格式,定义出来的,只是数组类型的变量而已,内存中还没有创建出数组容器。
1.2 数组静态初始化
初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程。
完整格式:
数据类型[] 数组名 = new 数据类型[] { 元素1,元素2,元素3… };
范例:
int[] array = new int[]{ 11,22,33 };
double[] array2 = new double[] { 11.1,22.2,33.3};
相对于完整格式,我们更常用的是简化格式:
数据类型[] 数组名 = { 元素1,元素2,元素3… };
范例:
int[] array = { 11,22,33 };
double[] array2 = { 11.1,22.2,33.3};
下面我们使用简化格式来定义数组并打印数组名:
package cn.edu.hgu.array;
public class ArrayDemo1 {
public static void main(String[] args) {
int[] array1 = {11, 22, 33};
System.out.println(array1);
double[] array2 = {44.4, 55.5, 66.6};
System.out.println(array2);
}
}
输出结果为:
输出结果并不是我们期望的数值,而是一串字符,下面我们来分析一下:
- @:分隔符
- [:当前空间是数组类型的
- I:当前数组类型,是 int 类型
- 4eec7777:数组的16进制内存地址
得出结论:打印数组名, 会看到数组在内存中的十六进制地址值
2. 数组元素访问
格式:
数组名[索引];
索引:索引是数组容器中空间的编号,编号从0开始,逐个+1增长
下面我们创建一个数组并进行访问:
package cn.edu.hgu.test;
public class ArrayTest1 {
public static void main(String[] args) {
arrayTest();
}
public static void arrayTest() {
int[] arr = {11, 22, 33, 44, 55};
// 取出数组中 22 元素,打印在控制台
System.out.println(arr[1]);
// 判断数组中第一个元素是奇数还是偶数
if (arr[0] % 2 == 0) {
System.out.println(arr[0] + "是一个偶数");
} else {
System.out.println(arr[0] + "是一个奇数");
}
//修改数组中第三个元素为 66
arr[2] = 66;
System.out.println(arr[2]);
// 根据数组中第四个元素,决定在控制台打印多少次 HelloWorld
for (int i = 1; i <= arr[3]; i++) {
System.out.println("HelloWorld");
}
}
}
输出结果为:
3. 数组遍历操作
3.1 数组遍历介绍
数组遍历:将数组中所有的内容取出来,取出来之后可以(打印,求和,判断…)
下面我们通过案例来说明,如何遍历一个数组:
package cn.edu.hgu.test;
public class ArrayTest2 {
public static void main(String[] args) {
printArray();
}
/*
数组遍历
*/
public static void printArray(){
int[] arr = {11,22,33,44,55};
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
输出结果为:
数组遍历快捷键:数组名.fori
3.2 数组遍历场景
那么,什么时候需要使用数组遍历呢?
如果要完成的需求,是需要操作到数组中的【每一个】元素,就需要对数组进行遍历操作
3.3 数组遍历案例
1)数组遍历-求偶数和
package cn.edu.hgu.test;
public class ArrayTest3 {
public static void main(String[] args) {
getSum();
}
public static void getSum() {
int[] arr = {11, 22, 33, 44, 55};
// 1.定义求和变量,准备进行累加操作
int sum = 0;
// 2.遍历数组,获取到每一个元素
for (int i = 0; i < arr.length; i++) {
// 3.判断当前元素是否为偶数
if (arr[i] % 2 == 0) {
// 4.是的话,进行累加求和
sum += arr[i];
}
}
// 5.遍历结束后,将求和结果打印
System.out.println("偶数和为:" + sum);
}
}
输出结果为:
2)数组遍历-求最大值
需求:已知数组元素为 {5,44,33,55,22} ,请找出数组中最大值并打印在控制台
分析:
- 定义 max 变量来记录擂台上不断变化的数据
- 数组中 0 号选手先上台,因此 int max = arr[0];
- 遍历数组取出每一个元素,索引从 1 开始
- 逐个进行比较,找到更大的,max变量记录更大的数据
- 遍历后打印 max 变量所记录的值
代码实现:
package cn.edu.hgu.test;
public class ArrayTest4 {
public static void main(String[] args) {
int[] arr1 = {33, 55, 11, 22, 44};
int[] arr2 = {100, 99, 66, 88, 77};
int max = getMax(arr2);
System.out.println("最大值为:" + max);
}
public static int getMax(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
}
输出结果为:
3)数组遍历综合案例
需求:已知班级学生成绩为 Int[ ] arr ={100,50,20,90,90};
- 找出数组最大值,并打印在控制台
- 找出数组最小值,并打印在控制台
- 求总成绩,并打印在控制台
- 计算出平均值,并打印在控制台
- 统计出低于平均值元素的个数
代码实现:
package cn.edu.hgu.test;
public class ArrayTest5 {
public static void main(String[] args) {
int[] arr = {100, 50, 20, 90, 90};
int max = getMax(arr);
System.out.println("最高分为:" + max);
int min = getMin(arr);
System.out.println("最低分为:" + min);
int sum = getSum(arr);
System.out.println("班级总成绩:" + sum);
double avg = getAvg(arr);
System.out.println("班级平均分为:"+avg);
int count = getCount(arr);
System.out.println("低于平均分的人数为:"+count);
}
/**
* 统计出低于平均值元素的个数
*/
public static int getCount(int[] arr){
int count = 0;
double avg =getAvg(arr);
for (int i = 0; i < arr.length; i++) {
if (arr[i]<avg){
count++;
}
}
return count;
}
/**
* 计算出平均值,并打印在控制台
*/
public static double getAvg(int[] arr){
double sum = getSum(arr);
double avg = sum/arr.length;
return avg;
}
/**
* 求总成绩,并打印在控制台
*/
public static int getSum(int[] arr) {
// 1.定义求和变量,准备进行累加操作
int sum = 0;
// 2.遍历数组,获取到每一个元素
for (int i = 0; i < arr.length; i++) {
// 3.判断当前元素是否为偶数
if (arr[i] % 2 == 0) {
// 4.是的话,进行累加求和
sum += arr[i];
}
}
// 5.遍历结束后,将求和结果返回
return sum;
}
/**
* 找出数组最大值,并打印在控制台
*/
private static int getMax(int[] arr) {
int max = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
return max;
}
/**
* 找出数组最小值,并打印在控制台
*/
private static int getMin(int[] arr) {
int min = arr[0];
for (int i = 1; i < arr.length; i++) {
if (arr[i] < min) {
min = arr[i];
}
}
return min;
}
}
输出结果为:
4. 数组动态初始化
4.1 数组动态初始化介绍
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
格式:
数据类型[] 数组名 = new 数据类型[数组长度];
范例:
int[] arr = new int[3];
那么我们知道了动态初始化的格式,那不同数据类型的初始值是一样的吗?下表是不同数据类型对应的默认值:
下面我们来使用一下数组动态初始化方法:
package cn.edu.hgu.array;
public class ArrayDemo2 {
public static void main(String[] args) {
arrayTest();
}
public static void arrayTest() {
//整数
int[] arr1 = new int[3];
for (int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("--------------");
//小数
double[] arr2 = new double[3];
for (int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
System.out.println("--------------");
//字符
char[] arr3 = new char[3];
for (int i = 0; i < arr3.length; i++) {
System.out.println(arr3[i]);
}
System.out.println("--------------");
//布尔
boolean[] arr4 = new boolean[3];
for (int i = 0; i < arr4.length; i++) {
System.out.println(arr4[i]);
}
System.out.println("--------------");
//字符串
String[] arr5 = new String[3];
for (int i = 0; i < arr5.length; i++) {
System.out.println(arr5[i]);
}
}
}
输出结果为:
通过上面的练习,我们了解了不同数据类型对应不同的初始值。
4.2 两种初始化的区别
- 动态初始化:手动指定数组长度,由系统给出默认初始化值。
- 静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度
使用场景:
-
静态初始化:如果要操作的数据,需求中已经明确出了,直接静态初始化
需求:已知班级学生成绩为 100 100 90 20 100,找出最高分
int[ ] arr = {100,100,90,20,100}
-
动态初始化:只明确元素个数,不明确具体数值
需求1:键盘录入 5 个学生成绩,找出最高分
需求2:产生10个1~100之间的随机数,找出最小值
4.3 数组动态初始化案例
1)使用键盘录入填充数组
需求:键盘录入5个整数并求出最大值
分析:
- 动态初始化数组,长度指定为5
- 循环遍历数组,在遍历的过程中,键盘录入整数并存入数组
- 求出数组最大值
- 打印数组
代码如下:
package cn.edu.hgu.test;
import java.util.Scanner;
import static cn.edu.hgu.test.ArrayTest4.getMax;
public class ArrayTest6 {
public static void main(String[] args) {
int[] arr = initArrayFromScanner();
int max = getMax(arr);
System.out.println("最大值为:" + max);
}
private static int[] initArrayFromScanner() {
Scanner sc = new Scanner(System.in);
System.out.println("键盘录入班级成绩,请输入班级人数");
int count = sc.nextInt();
int[] arr = new int[count];
for (int i = 0; i < arr.length; i++) {
System.out.println("请输入第" + (i + 1) + "个元素");
arr[i] = sc.nextInt();
}
return arr;
}
}
输出结果为:
思路积累:
如果只明确元素个数,不明确具体数值可以考虑使用动态初始化,将容器准备好,随后再对容器进行填充
2)使用随机数填充数组
需求:产生10个1-100之间的随机数,并找出最大值
分析:
- 动态初始化数组,长度指定为10
- 循环遍历数组,在遍历的过程中,产生随机数并存入数组
- 遍历打印出数组现有元素
- 求出最大值
- 打印最大值
代码实现:
package cn.edu.hgu.test;
import java.util.Random;
import static cn.edu.hgu.test.ArrayTest4.getMax;
public class ArrayTest7 {
public static void main(String[] args) {
int[] randomNums = new int[10];
Random r = new Random();
for (int i = 0; i < randomNums.length; i++) {
randomNums[i] = r.nextInt(100) + 1;
System.out.println(randomNums[i]);
}
int max = getMax(randomNums);
System.out.println("最大值为:" + max);
}
}
输出结果为:
5. 数组内存图
5.1 Java 内存分配介绍
- 栈
- 堆
- 方法区
- 本地方法栈
- 寄存器
简化格式只是简化了代码书写,真正运行期间还是按照完整格式运行的,int[] arr = new int[]{11,22,33};
5.2 方法的参数传递问题
方法的参数传递问题:
- 基本数据类型:传递的是数据值
- 引用数据类型:传递的是地址值
问题:Java到底是值传递,还是址传递?
回答:值传递,地址值也是值
代码如下:
package cn.edu.hgu.args;
public class ArgsTest1 {
public static void main(String[] args) {
int number = 100;
System.out.println("调用change方法前:"+number);
change(number);
System.out.println("调用change方法后:"+number);
}
public static void change(int number){
number = 200;
}
}
输出结果为:
调用change方法前:100
调用change方法后:100
修改一下上面的代码:
package cn.edu.hgu.args;
public class ArgsTest1 {
public static void main(String[] args) {
int number = 100;
System.out.println("调用change方法前:"+number);
number = change(number);
System.out.println("调用change方法后:"+number);
}
public static int change(int number){
number = 200;
return number;
}
}
输出结果为:
调用change方法前:100
调用change方法后:200
下面我们来看一下对数组进行操作:
package cn.edu.hgu.args;
public class ArgsTest1 {
public static void main(String[] args) {
int[] arr = {11,22,33,44,55};
System.out.println("调用change方法前:"+arr[0]);
change(arr);
System.out.println("调用change方法后:"+arr[0]);
}
public static void change(int[] arr){
arr[0] = 66;
}
}
输出结果为:
调用change方法前:11
调用change方法后:66
总结,对于基本数据类型,传递的是数据值,在方法里不能直接修改;对于引用数据类型,传递的是地址值,方法会根据地址值找到数据所在的位置,从而对数据进行修改。
6. 数组常见问题
6.1 索引越界异常
ArrayIndexOutOfBoundsException 当访问了数组中不存在的索引,就会引发索引越界异常
我们通过案例来了解一下:
package cn.edu.hgu.exception;
public class ArrayIndexOutOfBoundsExceptionDemo {
public static void main(String[] args) {
int[] arr ={11,22,33};
System.out.println(arr[10]);
}
}
输出异常:
就是说,我们的数组长度为3,但使用的索引10超出了范围。
6.2 空指针异常
当引用数据类型变量被赋值为 null 之后,地址的指向被切断,还继续访问堆内存数据,就会引发空指针异常
演示如下:
package cn.edu.hgu.exception;
public class NullPointerExceptionDemo {
public static void main(String[] args) {
int[] arr ={11,22,33};
arr = null;
System.out.println(arr[0]);
}
}
输出结果为:
三、二维数组
1. 二维数组介绍
二维数组是一种容器,该容器用于存储一维数组。
如果销售部门要根据季度进行分组,那么一维数组就不太适合了。
使用思路:
今后若要操作的 多组 数据,属于同一组数据就可以考虑使用二维数组行维护
2. 二维数组静态初始化
2.1 二维数组静态初始化格式
格式:
数据类型[][] 数组名 = new 数据类型[][] {{元素1,元素2},{元素1, 元素2}};
范例:
int[][] arr = new int[][]{{11,22},{33,44}};
简化格式:
数据类型[][] 数组名 = {{元素1,元素2}, {元素1, 元素2}};
范例:
int[][] arr = {{11,22},{33,44}};
我们来练习一下吧:
package cn.edu.hgu.array2;
public class ArrayDemo1 {
public static void main(String[] args) {
int[][] arr = {
{11, 22, 33},
{44, 55, 66}
};
System.out.println(arr);//[[I@4eec7777
System.out.println(arr[0]);//[I@3b07d329
System.out.println(arr[1]);//[I@41629346
}
}
细节:二维数组在储存一维数组的时候,具体储存的是一维数组的地址值
2.2 二维数组元素访问
格式:
数组名[m索引][n索引];
- m索引:指定访问哪一个一维数组
- n索引:访问一维数组中的哪一个元素
范例:
int[][] arr = new int[][]{{11,22},{33,44}};arr[1][0];
代码实现:
package cn.edu.hgu.array2;
public class ArrayDemo1 {
public static void main(String[] args) {
int[][] arr = {
{11, 22, 33},
{44, 55, 66}
};
System.out.println(arr[1][1]);//55
System.out.println(arr[0][2]);//33
}
}
3. 二维数组遍历
使用双重循环来解决问题。
案例:二维数组遍历-打印
需求:已知一个二维数组 arr = { {11 , 22 , 33} , {33 , 44 , 55} }; 遍历该数组,打印元素并求和。
分析:
- 遍历二维数组,取出里面每一个一维数组
- 在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素
代码实现:
package cn.edu.hgu.test;
public class ArrayTest8 {
public static void main(String[] args) {
int[][] arr = {
{11, 22, 33},
{33, 44, 55}
};
printArray(arr);
}
/**
* 打印二维数组
*/
public static void printArray(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
}
输出结果为:
案例:二维数组遍历-求和
需求:已知一个二维数组 arr = { {11 , 22 , 33} , {33 , 44 , 55} }; 对内部存储的元素累加求和,并将结果输出在控制台
分析:
- 定义求和变量
- 遍历二维数组,取出里面每一个一维数组
- 在遍历的过程中,对每一个一维数组继续完成遍历,获取内部存储的每一个元素
- 求和累加
- 打印求和结果
我们在上一个案例的基础上进行改造:
package cn.edu.hgu.test;
public class ArrayTest8 {
public static void main(String[] args) {
int[][] arr = {
{11, 22, 33},
{33, 44, 55}
};
printArray(arr);
int sum = getSum(arr);
System.out.println("二维数组和为:" + sum);
}
/**
* 打印二维数组
*/
public static void printArray(int[][] arr) {
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
/**
* 二维数组求和
*/
public static int getSum(int[][] arr) {
int sum = 0;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
sum += arr[i][j];
}
}
return sum;
}
}
输出结果为:
4. 二维数组动态初始化
二维数组动态初始化格式:
数据类型[][] 数组名 = new 数据类型[m][n];
- m表示这个二维数组,可以存放多少个一维数组
- n表示每一个一维数组,可以存放多少个元素
范例:
int[][] arr = new int[2][3];
该数组可以存放2个一维数组,每个一维数组中可以存放3个int类型元素
是否可以将创建好的一维数组,存入二维数组?可以
package cn.edu.hgu.array2;
public class ArrayDemo2 {
public static void main(String[] args) {
// 该数组可以存放2个一维数组,每个一维数组中可以存放3个int类型元素
int[][] arr = new int[2][3];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
int[] arr1 = {11,22,33};
int[] arr2 = {44,55,66};
arr[0] = arr1;
arr[1] = arr2;
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[i].length; j++) {
System.out.println(arr[i][j]);
}
}
}
}
输出结果为: