一、数组介绍
1. 什么是数组?
数组指的是一种容器,可以用来存储同种数据类型的多个值
-
数组容器在存储数据的时候,需要结合隐式转换考虑
- 例如:int 类型的数组容器可以存(byte,short,int)
- 例如:double类型的数组容器可以存(byte,short,int,long,float,double)
- 建议:容器的类型,和存储的数据类型保持一致
二、数组的定义与静态初始化
1. 数组的定义
格式一
数据类型[] 数组名
格式二
数据类型 数组名[]
2. 数组的静态初始化
- 初始化:就是在内存中,为数组容器开辟空间,并将数据存入容器中的过程
完整格式: 数据类型[] 数组名 = new 数据类型[]{元素1,元素2,元素3...};
范例:int[] arr = new int[]{1,2,3};
简化格式:数据类型[] 数组名 = {元素1,元素2,元素3...};
范例:int[] arr = {1,2,3};
public class ArrayDefine {
public static void main(String[] args) {
int[] arr1 = new int[]{1,2,3,4};
int[] arr2 = {1,2,3,4};
String[] arr3 = new String[]{"张三", "李四", "王五"};
String[] arr4 = {"张三", "李四", "王五"};
double[] arr5 = new double[]{1.1,1.2,1.3};
double[] arr6 = {1.1,1.2,1.3};
}
}
3. 数组的地址值
int[] arr = new int[]{1,2,3,4,5};
System.out.println(arr); // [I@6d03e736 地址值
数组的地址值表示数组在内存中的位置
解释地址值的格式含义 [I@6d03e736
[:表示当前是一个数组
I:表示当前数组里面的元素都是 int 类型的
@:表示一个间隔符号(固定格式)
[I@6d03e736:才是数组真正的地址值(十六进制)
平时习惯将这个整体称为数组的地址值
三、数组元素访问
1. 数组元素访问
格式:数组名[索引];
2. 索引
索引:也叫下标,角标;
索引的特点:从0开始,逐个+1增长,连续不间断
public class ArrTest3 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
// 数组长度:数组的 length 属性
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
四、数组遍历
1. 数组遍历
数组遍历:将数组中所有的内容取出来,取出来之后可以(打印、求和、判断...)
注意:遍历指的是取出数据的过程,不要局限的理解为,遍历就是打印
public class ArrTest3 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
// 数组长度:数组的 length 属性
for(int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
练习:遍历数组并求和
定义一个数组,存储1,2,3,4,5
遍历数组得到每一个元素,求数组里面所有的数据和
public class ArrTest6 {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 2 == 0) {
arr[i] = arr[i] / 2;
} else {
arr[i] = arr[i] * 2;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
练习:统计个数
定义一个数组,存储1,2,3,4,5,6,7,8,9,10
遍历数组得到每一个元素,统计数组里面一共有多少个能被 3 整除的数字
public class ArrTest6 {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 2 == 0) {
arr[i] = arr[i] / 2;
} else {
arr[i] = arr[i] * 2;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
练习:变化数据
定义一个数组,存储1,2,3,4,5,6,7,8,9,10
遍历数组得到每一个元素
要求:
如果是奇数,则将当前数字扩大两倍
如果是偶数,则将当前数字变成二分之一
public class ArrTest6 {
public static void main(String[] args) {
int[] arr = new int[]{1,2,3,4,5,6,7,8,9,10};
for (int i = 0; i < arr.length; i++) {
if (arr[i] % 2 == 0) {
arr[i] = arr[i] / 2;
} else {
arr[i] = arr[i] * 2;
}
}
for (int i = 0; i < arr.length; i++) {
System.out.println(arr[i]);
}
}
}
五、数组动态初始化
1. 为什么有数组动态初始化呢
- int[] arr = {1,2,3,4,5};
- int[] arr = {???};
2. 数组动态初始化
动态初始化:初始化时,只指定数组长度,由系统为数组分配初始值
- 格式:数据类型[] 数组名 = new 数据类型[数组长度];
- 范例:int[] arr = new int[3];
public class AttTest7 {
public static void main(String[] args) {
String[] arr = new String[50];
arr[0] = "张三";
arr[1] = "李四";
System.out.println(arr[0]); // 张三
System.out.println(arr[1]); // 李四
System.out.println(arr[2]); // 打印出来的是默认初始化值 null
int[] arr2 = new int[3];
System.out.println(arr2[0]); // 0
System.out.println(arr2[1]); // 0
System.out.println(arr2[2]); // 0
}
}
3. 数组动态初始化和静态初始化的区别
- 动态初始化:手动指定数组长度,由系统给出默认初始化值
- 只明确元素个数,不明确具体数值,推荐使用动态初始化
- 举例:使用数组容器来存储键盘录入的5个整数
- int[] arr = {?????};
- int[] arr = new int[5];
- 只明确元素个数,不明确具体数值,推荐使用动态初始化
- 静态初始化:手动指定数组元素,系统会根据元素个数,计算出数组的长度
- 需求中已经明确了要操作的具体数据,直接静态初始化即可
- 举例:将全班的学生成绩存入数组中 11,22,33
- int[] arr = {11,22,33};
- 需求中已经明确了要操作的具体数据,直接静态初始化即可
4. 数组默认初始化值的规律
- 整数类型:默认初始化值 0
- 小数类型:默认初始化值 0.0
- 字符类型:默认初始化值 '/u0000' 空格
- 布尔类型:默认初始化值 false
- 引用数据类型:默认初始化值 null
六、数组内存图
1. Java内存分配
- 栈:方法运行时使用的内存,比如 main 方法运行,进入方法栈中执行
- 堆:存储对象或者数组,new 来创建的,都存储在堆内存
- 方法区:存储可以运行的 class 文件
- 本地方法栈:JVM 在使用操作系统功能的时候使用,和开发无关
- 寄存器:给 CPU 使用,和开发无关
2. 数组存储
-
- 只要是 new 出来的一定是在 堆 里面开辟了小空间
-
- 如果 new 了很多次,那么在 堆 里面有很多小空间,每个小空间中都有各自的数据
3. 两个数组指向同一个空间的内存图
-
- 当两个数组指向同一个小空间时,其中一个数组对小空间中的值发生了改变,那么其它数组再次访问的时候都是修改之后的结果了
七、数组常见问题
1. 数组常见问题
- 当访问了数组中不存在的索引,就会引发
索引越界异常 - 索引范围
- 最小索引:0
- 最大索引:(数组长度 - 1)
public class ArrTest8 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
// Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: Index 5 out of bounds for length 5 at com.hrwar.test.ArrTest8.main(ArrTest8.java:6)
System.out.println(arr[5]);
}
}
八、数组常见操作
1. 求最值
需求:已知数组元素为{33,5,22,44,55}
请找出数组中最大值并打印在控制台
public class ArrTest9 {
public static void main(String[] args) {
int[] arr = {33,5,22,44,55};
int max = arr[0];
for (int i = 0; i < arr.length; i++) {
if (arr[i] > max) {
max = arr[i];
}
}
System.out.println(max);
}
}
- 扩展
-
- 根据求最大值的思路,改写一个最小值
-
- 为什么max要记录为arr[0],默认不能为 0 吗?
- 不能,可能是全 负 数组
-
- 循环中开始条件一定是 0 吗?
- 不一定,可自定义
-
2. 求和
需求:生成10个1~100之间的随机数存入数组
求出所有数据的和
求所有数据的平均数
统计有多少个数据比平均值小
import java.util.Random;
public class ArrTest10 {
public static void main(String[] args) {
int[] arr = new int[10];
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
int number = r.nextInt(100) + 1;
arr[i] = number;
}
int sum = 0;
for (int i = 0; i < arr.length; i++) {
sum += arr[i];
}
System.out.println("数组中所有数据的和为:" + sum);
int avg = sum / arr.length;
System.out.println("数组中平均数为:" + avg);
int count = 0;
for (int i = 0; i < arr.length; i++) {
if (arr[i] < avg) {
count++;
}
}
System.out.println("在数组中,一共有" + count + "个数据,比平均数小");
// 遍历数组,验证答案
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
3. 交换数据
需求:定义一个数组,存入1,2,3,4,5。按照要求交换索引对应的元素
交换前:1,2,3,4,5
交换后:5,4,3,2,1
public class ArrTest11 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
for (int i = 0, j = arr.length - 1; i < j; i++, j--) {
int temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}
4. 打乱数据
需求:定义一个数组,存入1~5,要求打乱数组中所有数据的顺序
import java.util.Random;
public class ArrTest12 {
public static void main(String[] args) {
int[] arr = {1,2,3,4,5};
Random r = new Random();
for (int i = 0; i < arr.length; i++) {
int randomIndex = r.nextInt(arr.length);
int temp = arr[i];
arr[i] = arr[randomIndex];
arr[randomIndex] = temp;
}
for (int i = 0; i < arr.length; i++) {
System.out.print(arr[i] + " ");
}
}
}