第四章 数组
今日内容
数组概念
数组的定义
数组的索引
数组内存
数组案例
排序算法
可变参数列表二维数组
1.数组概述
数组,表示一块连续的内存空间,可用来存储多个数据(元素),要求元素类型要一致。
数组初识:
1)如果有五个数据1 2 3 4 5,需要去接收、保存、操作这些数据,需要五个变量
int a1 = 1;
int a2 = 2;
int a3 = 3;
int a4 = 4;
int a5 = 5;
// int类型变量,用来标识1块内存,只能用来存放1个数值
2)现在有了数组,我们可以使用一个数组来存储这五个数据
int[] arr = {1,2,3,4,5};
// 这里使用一个数组来保存这5个元素值
// 数组表示一块连续的内存空间,可以用来存放多个元素值
3)我们对数组其实不陌生,之前课程已经接触过,大家可看下面代码
//这个参数args的类型是字符串数组
public static void main(String[] args) {
// 注意:下面代码看不懂没有关系,本章学完能看懂即可
//控制循环输出的次
int num = 1;
//如果main方法的参数args有接收到参数值的话
if(args.length > 0) {
//把接收到的值转换为int类型,并赋值给变量num
num = Integer.parseInt(args[0]);
}
//循环输出hello,默认输出次数为1,如果用户给main方法传参了,则按照用户的要求的次数进行输出
for(int i = 0; i < num; i++) {
System.out.println("hello");
}
}
2.数组定义
数组的定义有2种格式,分别如下:
数据类型[] 数组名; (推荐用法)示例:
int[] arr;
double[] arr;
char[] arr;
数据类型 数组名[];
示例:
int arr[];
double arr[];
char arr[];
两种方式都可以定义数组,我们推荐第一种用法!数组内存理解
public static void main(String[] args){
// 定于变量a
int a;
// 定义变量b并初始化
int b = 10;
// 定义数组arr,注意未初始化
int[] arr;
// 编译报错
//System.out.println(a); System.out.println(b);
// 编译报错
//System.out.println(arr);
}
注意1:数组是引用数据类型,用来存储一个引用值(可理解为地址值)注意2:数组没有进行初始化,不可以直接使用
3.数组初始化
定义数组(开辟栈空间内存)的同时,给其赋上初值,就叫做数组的初始化!
动态初始化
格式:
数据类型[] 数组名 = new 数据类型[数组长度];
案例:
int[] arr1 = new int[3];
double[] arr2 = new double[2];
String[] arr3 = new String[4];
注意:new 是一个关键字,表示为数组开辟内存空间
等号两边的数据类型要一致(先记住,后期会补充不一致的情况)数组长度必须要有,可以>=0(一般大于0),但不能为负数
- 内存构成
数组名标识的那块内存(栈空间),存放了一个引用值(地址值),通过该地址值可以找到堆空间相应内存(用来存放数组中所有元素)。
堆空间内存存在默认初始化:整形数初始化为0,浮点数0.0,引用类型
null,字符类型初始化 \u0000
public class Test032_Memory {
// 借助下面案例,可以验证上图
public static void main(String[] args) {
// 定义并初始化数组arr
int[] arr = new int[4];
/* 验证:上图中堆空间的存在 */
/* 输出结果为:[I@15db9742
* [ : 当前的空间是一个数组类型
* I : 当前数组容器中所存储的数据类型
* @ : 分隔符
* 15db9742 : */
堆空间十六进制内存地址
System.out.println(arr); System.out.println("-------------------");
/* 验证:元素初始值为0 */
// 访问数组元素可以通过数组下标来实现,具体格式:数组名[下标]
// 注意,下标从0开始,最大值为 数组长度-1
System.out.println(arr[0]);
//第1个元素
System.out.println(arr[3]);
//第4个元素
System.out.println("-------------------");
//数组的遍历
for(int i = 0; i < 4; i++) {
System.out.println(arr[i]);
}
}
- 数组下标
数组的下标的区间为 [0, 数组长度-1] 。
如果数组长度为 length ,那么数组下标的最小值为0,下标最大值为length-1 。
通过下标可以访问数组中元素:
//数组长度为4,那么其下标就是0~3
int[] arr = new int[4];
//可以通过下标获取数组元素值System.out.println(arr[0]); System.out.println(arr[3]);
通过数组下标给数组元素赋值:
int[] arr = new int[4]; arr[0] = 337;
arr[1] = 340; arr[2] = 348; arr[3] = 352;
结合循环来赋值或者取值:
int[] arr = new int[4];
//数组下标的取值范围,从0开始,到数组长度-1
for(int i = 0; i < 4; i++){
arr[i] = 10 + i;
}
//获取数组每个元素的值,并且输出for(int i = 0; i < 4; i++){
System.out.println(arr[i]); }
- 数组长度
数组长度,是指在一个数组中,可以存放同一类型元素的最大数量。获取数组长度固定格式: 数组名.length
int[] arr = new int[4]; System.out.println(arr.length);
数组长度注意事项:
数组长度,必须在创建数组对象的时候就明确指定数组长度,一旦确定,就无法再改变
数组长度,可以>=0(一般大于0),但不能为负数
借助循环赋值或遍历的最终形式:package com.briup.chap04; public class Test035_Length {
public static void main(String[] args) {
int[] arr = new int[4];
//遍历数组中初始元素值,默认为0
for(int i = 0; i < arr.length; i++){
System.out.println(arr[i]);
}
System.out.println("--------------");
//逐个元素赋值,借助 数组名.length 完成for(int i = 0;i < arr.length; i++){
arr[i] = 10 + i; }
//遍历数组中所有元素值
for(int i = 0; i < arr.length; i++){ System.out.println(arr[i]);
}
}
}
- 数组默认值
数组在创建时,会开辟2块内存,数组名对应栈空间那块内存,数组元素会存放在堆空间。
堆空间数组每一个元素位置上,存在相应的默认值,要么为0,要么为0.0,要么为null。
//byte、short、int、long类型数组中的默认值为 0
//例如
int[] a = new int[4];//默认4个数据全是0
//float、double类型数组中的默认值为 0.0
double[] d = new double[4];//默认4个数据全是0.0
//boolean类型数组中的默认值为 false
boolean[] d = new boolean[4];//默认4个数据全是false
//char类型数组中的默认值为 '\u0000'
char[] d = new char[4];//默认4个数据全是'\u0000'
//引用类型数组中的默认值为 null【不理解引用类型没关系,后续会补充】String[] d = new String[4];//默认4个数据全是null
- 静态初始化
在创建数组的同时,直接初始化数组元素的值,称为数组的静态初始化。静态初始化格式:
完整版格式
数据类型[] 数组名 = new 数据类型[]{元素1,元素2,...};
简化版格式
数据类型[] 数组名 = {元素1,元素2,...};
注意:数组静态初始化书写方式要严格按照上述两种方式!
示例:下面以创建int类型数组对象进行说明
//数组静态初始化
public class Test036_Init {
//定义一个方法,专门输出数组元素
public static void outArray(int[] arr) { for(int i = 0; i < arr.length; i++) {
System.out.println("arr[" + i + "]: " + arr[i]); }
}
public static void main(String[] args) {
// 完整版本静态初始化
int[] arr1 = new int[]{1,3,5,7,9};
outArray(arr1);
Sytem.out.println("--------------");
// 简化版本静态初始化
int[] arr2 = {1,3,5,7,9};
outArray(arr2);
System.out.println("--------------");
// 先定义数组名【在栈空间开辟内存】
int[] arr3;
// 再去堆空间开辟内存并静态初始化,然后将堆空间地址值 放入 (数组名标识的)栈空间内存
arr3 = new int[]{1,3,5,7,9}; outArray(arr3);
}
}
下面是错误写法:
public static void main(String[] args) {
//省略...
//错误方式1:不能明确数组长度
int[] arr4 = new int[3]{1,2,3};
//错误方式2:简化版格式必须严格按照上述格式书写,不能分两行书写int[] arr5;
arr5 = {1,2,3}; }
- 内存补充
1、两个数组内存结构图
public class Test037_Extend {
public static void main(String[] args) {
int[] arr1 = new int[] {1,2,3};
int[] arr2 = {4,5};
System.out.println(arr1); //[I@15db9742
System.out.println(arr2); //[I@6d06d69c
System.out.println("--------------");
for(int i = 0; i < arr1.length; i++) { System.out.println(arr1[i]);
}
System.out.println("--------------");
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
}
}
内存结构图如下:
2、使用数组赋值
public class Test037_Extend2 {
public static void main(String[] args) {
int[] arr1 = new int[] {1,2,3};
System.out.println(arr1); //[I@15db9742
int[] arr2 = arr1;
System.out.println(arr2); //[I@15db9742
System.out.println("--------------");
for(int i = 0; i < arr1.length; i++) {
System.out.println(arr1[i]);
}
System.out.println("--------------");
for(int i = 0; i < arr2.length; i++) {
System.out.println(arr2[i]);
}
}
}
内存结构图如下:
4.数组异常
使用数组的过程中,经常会遇到以下2种异常,具体如下:
- 索引越界
出现原因
public class Test041_IndexOut {
public static void main(String[] args) {
int[] arr = new int[4];
//数组下标最大取值为3,现在取4,超出了范围,会产生索引越界异常
System.out.println(arr[4]);
}
}
程序运行后,将会抛出 ArrayIndexOutOfBoundsException 数组越界异常。
在开发中,数组越界异常是不能出现的,一旦出现了,就必须要修改代码。
解决方案
将错误的索引修改为正确的索引范围即可!
- 空指针
出现原因
public class Test042_NullPointer {
public static void main(String[] args) {
int[] arr = new int[3];
//把null赋值给数组
arr = null; System.out.println(arr[0]);
}
}
arr = null 这行代码,意味着变量arr将不再保存数组的内存地址,我们通过arr这个标识符再也找不到堆空间数组元素,因此运行的时候会抛出
NullPointerException 空指针异常。
在开发中,空指针异常是不能出现的,一旦出现了,就必须要修改代码。解决方案
给数组一个真正的堆内存空间引用即可
5.工具类
java.util.Arrays 类,是JavaSE API中提供给我们使用的一个工具类,这个类中包含了操作数组的常用方法,比如排序、查询、复制、填充数据等,借助它我们在代码中操作数组会更方便。
Arrays中的常用方法:
toString方法
可以把一个数组变为对应的String形式copyOf方法
可以把一个数组进行复制
该方法中也是采用了arraycopy方法来实现的功能
sort方法
可以对数组进行排序
binarySearch方法
在数组中,查找指定的值,返回这个指定的值在数组中的下标,但是查找之前需要在数组中先进行排序,可以使用sort方法先进行排序
copyOfRange方法(了解)
也是复制数组的方法,但是可以指定从哪一个下标位置开始复制该方法中也是采用了arraycopy方法来实现的功能
fill(了解)
可以使用一个特定的值,把数组中的空间全都赋成这个值案例展示:
import java.util.Arrays; public class Test05_Arrays {
public static void main(String[] args) {
int[] a = {1,3,5,2,6,8};
//获取数组的字符串形式并输出
System.out.println(Arrays.toString(a));
//借助工具类完成数组拷贝
a = Arrays.copyOf(a,10);
//思考:数组的长度不能修改,此时a长度变成了10,如何解释?System.out.println(a.length); System.out.println(Arrays.toString(a));
//对数组排序
Arrays.sort(a); System.out.println(Arrays.toString(a));
//二分查找
int index = Arrays.binarySearch(a,5);
System.out.println(index);
//数组元素填充
Arrays.fill(a,100); System.out.println(Arrays.toString(a));
}
}
友友们,预防睡着,下篇继续00000!