数组
- 为解决多个变量存储问题。
数组的定义
- 数组(array):是一种用于存储多个相同数据类型的存储模型(可以理解为容器)
数组定义和静态初始化
数组有两种定义格式:
- 格式1:数据类型[] 变量名
- 范例: int[] arr;
- 定义了一个int类型的数组,数组名是arr-
- 格式2:数据类型 变量名[];
- 范例: int arr[];
- 定义了一个int类型的变量,变量名是arr数组
数组的初始化
- java中数组的使用必须先初始化才能使用
- 初始化含义:为数组中的数组元素分配内存空间,并为每个数组元素赋值。
- 注意:数组中的每一个元素,我们称之为数组中的元素
数组初始化的方式
- 数组初始化分为两种方式:一种是静态初始化,一种是动态初始化
静态初始化
- 静态初始化: 初始化时指定每个数组元素的初始值,由系统决定数组长度。
- 格式: 数据类型[] 变量名 =new 数据类型[]{数据1,数据2,数据3,…}
- 范例: int[] arr=new int[] {1,2,3}
- 简化格式: 数据类型[] 变量名={数据1,数据2,数据3…}
- 范例: int[] arr={1,2,3};
数组元素访问(获取和修改)
数组元素访问主要学习两方面的知识
- 数组变量的访问方式
- 数组内部保存的数据的访问方式
数组变量访问方式
数组变量访问方式:
- 格式:数组名
- 我们可以通过输出语句,输出数组名,就能够得
-到一个数据。
数组内部保存的数据的访问方式
- 格式:数组名[索引]
- 计算机中编号从0开始
索引
- 索引是数组中数据的编号方式
- 作用:用于访问数组中的数据使用,数组名[索引]等同于变量名,是一种特殊的变量名。
索引的特征
①:索引从0开始。
②:索引是连续的
③:索引逐一增加,每次加1
使用演示
package com.itheima_01;
/*
数组变量访问方式
格式:数组名
数组内部保存的数据的访问方式
格式:数组名[索引]
*/
public class ArrayTest {
public static void main(String[] args) {
// 定义一个数组并初始化
// int[] score = new int[]{93, 96, 99};
int[] score = {93, 96, 99};
// 输出数组
System.out.println(score[0]);
System.out.println(score[1]);
System.out.println(score[2]);
System.out.println("-------------");
// 修改数组中的元素
score[0] = 100;
score[1] = 98;
score[2] = 95;
System.out.println(score[0]);
System.out.println(score[1]);
System.out.println(score[2]);
}
}
案例1(数组常见操作遍历数组)
- 遍历
- 获取最大值
- 元素打乱
数组遍历
- 数组遍历指的是:获取数组中的每一个元素,我们可以把获取到的元素输出在控制台
package com.itheima_02;
public class ArrayDemo01 {
public static void main(String[] args) {
// 定义数组并初始化
int[] arr={77,88,99,66,55,44};
for (int i = 0; i < arr.length ; i++) {
System.out.println(arr[i]);
}
}
}
数组遍历:
- 获取数组中的每一个元素,把获取的元素输出到控制台。
获取数组长度(元素个数) - 格式: 数组名.length
- 范例:arr.length
数组遍历通用格式:
int[] arr={…};
for(int i=0;i<arr.length;i++){
arr[i];//对元素arr[i]进行操作
} - 注意:数组遍指的是把数组中的元素取出来,取出来之后可以(打印,求和,判断…)
- 数组遍历通用格式:
for(int i=0;i<scores.length;i++){
score[i]
}
注意:数组遍历指的是把数组中的元素取出来,取出来之后可以(打印,求和,判断…)
案例2(数组常见操作之获取最大值)
我这里有一个数组,我现在要获取数组中的最大值
思路:
1:因为我们最终,要得到最大值,所以,这里我们定义一个变量,用于保存最大值。
但是,它没有初始值,给多少比较合适呢?我总不能拿数组以外的数据进来吧,因为我们最终获取的是数组中的最大值。所以,我们就要从数组中找一个值作为初始值。
一般来说,我们取数组中第一个元素作为参照值。
2:这样我们的最大值变量就有初始值了,接下来,我们与数组中剩余的数据逐个比较,比完之后,max中最终保存的是最大值。
这个动作怎么实现呢?我们来说一下:获取索引1-4,为什么不从0开始呢?因为0索引位置的值已经作为初始值了。
3:我们每次比较,需要把最大值保存到max变量中,这个动作,我们可以通过if语句实现。
4:当循环结束后,打印max变量就可以了,这个max里面保存的就是最大值。
package com.itheima_02;
/*
获取最大值
*/
public class ArrayDemo02 {
public static void main(String[] args) {
// 定一个数组
int[] arr = {14, 15, 16, 96, 56};
// 定义一个变量存储最大值
int max = arr[0];
// 遍历数组
for (int i = 1; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println(max);
}
}
案例3(数组常见操作之元素打乱)
- 什么是元素打乱?
- 元素打乱就是把数组中的元素随机交换位置,每次运行都可能产生不一样的结果
比如:arr = {12, 45, 98, 73, 60};
遍历: - 正常情况下:12,45,98,73,60
- 元素打乱后:45,73,12,60,98
涉及到的操作: - 获取数组中元素的随机索引
- Random r = new Random();
- int index = r.nextInt(arr.length);
- 数组中元素交换
package com.itheima_02;
import java.util.Random;
/*
元素打乱
*/
public class ArrayDemo03 {
public static void main(String[] args) {
int[] arr = {12, 45, 98, 73, 60};
Random rd = new Random();
for (int i = 0; i < arr.length; i++) {
int index = rd.nextInt(arr.length);
int temp = arr[i];
arr[i] = arr[index];
arr[index] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
- 注意:通过random生成随机数,用过nextInt设置数据的上边界,此时index会随机生成0~4的任意数值,通过将随机的两个数组交换打乱数组顺序。
public int nextInt(int bound)
返回从此随机数生成器的序列中提取的伪随机,均匀分布的值在0(包括)和指定值(不包括)之间的int值。 nextInt的一般合同是伪随机生成并返回指定范围内的一个int值。 所有bound可能的int值以(近似)相等的概率产生。 方法nextInt(int bound)由类Random实现,
数组动态初始化
- 动态初始化时只指定数组长度,由系统为数组分配初始值
- 格式: 数据类型[] 变量名 = new 数据类型[数组长度];
package com.itheima_03;
/*
动态初始化:初始化时只指定数组长度,由系统为数组分配初始值
格式:数据类型[] 变量名 = new 数据类型[数组长度];
范例:int[] arr = new int[3];
*/
public class ArrayDemoTest {
public static void main(String[] args) {
// 格式:数据类型[] 变量名 =new 数据类型[数组长度];
int arr[] = new int[3];
// 输出数组地址
System.out.println(arr);
// 输出数组变量值
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
System.out.println("-------------");
// 修改数组中的元素
arr[0] = 10;
arr[1] = 20;
arr[2] = 30;
// 再次输出数组中的元素
System.out.println(arr[0]);
System.out.println(arr[1]);
System.out.println(arr[2]);
}
}
总结一下数组初始化的两种方式的**各自使用场景:
- 静态初始化: 开始就存入元素值,适合一开始就能确定元素值的业务场景
- 动态初始化: 指定数组长度,后期赋值,适合开始知道数据的数量,但是不确定具体元素值的业务场景
- 注意: 两种初始化的方式是独立的,不可以混用
案例4(数组来自键盘录入)
需求: 定义一个可以存储5个元素的int数组,数据来自于键盘录入,最后遍历数组,把元素输出在控制台
package com.itheima_03;
import java.util.Scanner;
public class ArrayTestScanner {
public static void main(String[] args) {
//首先不知道数组内容,动态初始化
int[] arr = new int[5];
// 创建键盘录入对象
Scanner sc = new Scanner(System.in);
for (int i = 0; i < arr.length ; i++) {
System.out.println("请输入第"+(i+1)+"个元素");
arr[i]= sc.nextInt();
}
printArray(arr);
}
public static void printArray(int[] arr){
System.out.println("[");
for (int i = 0; i < arr.length; i++) {
if (i== arr.length-1){
System.out.println(arr[i]);
}else {
System.out.println(arr[i]+",");
}
}
System.out.println("]");
}
}
注意 : bug产生原因,数组名设置为arr,调用数组长度却是arg.length注意这一点错误
数组内存图
- 程序从mian方法开始执行
- 内存图绘制
数组使用中的两个小问题
①索引越界:访问了数组中不存在的索引对应的元素,造成索引越界问题
- 最终结论:
- 有问题
- 访问了不存在的索引位置的元素
- 修改不存在索引为正确的索引。范围(0-数组长度-1)
②空指针异常:对象不再志向堆内存,还想继续访问数据,访问失败
最终结论是:
-
有问题
-
对象设置为null,不在指向堆内存数据了,还想继续访问堆内存数据
-
对象在使用前,进行不为null的判断
-
注意根据内存图来看,空指针异常时栈内存的内存地址指向为空,无法找到在堆内存中存储的数据。