【Java数组】

本文详细介绍了Java中的数组,包括声明方式(动态和静态初始化)、数组结构(存储在栈和堆中,通过地址访问元素),以及如何遍历和操作数组。还特别提到了数组越界问题和使用Arrays类进行排序、复制、填充等操作。最后,文章讨论了二维数组的概念和声明方式。
摘要由CSDN通过智能技术生成

Java数组

数组是在程序设计中,为了方便处理,把具有相同数据类型的数据按有序的形式组织起来的一种形式。这些有序排列的同类元素的集合就是称为数组。

不同的编程语言对数组的定义也不尽相同,有的语言在一个数组中可以存放不同类型的数据,而有的语言则是规定数组中的元素必须是相同数据类型。Java中的数组,其数组中的所有元素具有相同的数据类型。

数组的声明

基础语法结构

数据类型[] 数组名 = new 数据类型[ 常量表达式 ];

数据类型[] 数组名 = new 数据类型[]{ 初始化数据 };

数据类型[] 数组名 = { 初始化数据 }

示例

//声明可存储10个int类型变量的数组 元素的默认值为数据类型的默认值
int[] arr = new int[10];

//动态初始化 声明可存储10个int类型变量的数组并将其中的元素都初始化为1
int[] arr = new int[]{1,1,1,1,1,1,1,1,1,1};

//静态初始化 声明可存储10个int类型变量的数组并将其中的元素都初始化为1
int[] arr = {1,1,1,1,1,1,1,1,1,1};

上诉三种方式都可以声明一个可存储10个int类型变量的数组,在声明一个数组时都是需要对其元素进行初始化,第一种方式是将其初始化为对应数据类型的默认值,而后两种则是可以自定义初始化的值,不过也是得是符合相同数据类型的值才可以,根据初始化自定义值的数量来确定数组的大小。

数组的结构

Java基础数据类型中提到,数组是引用数据类型,其在内存中的存储形式是在栈区中存储地址,而在堆区中存储对象本身,通过地址去访问堆区中的元素。

请添加图片描述

数组名存储了堆区中数组首元素的地址,而元素在内存中的存储是有序的,且也是根据不同的数据类型来分配空间,当数组为int类型时,其每个元素占用4个字节的大小。

通过[]+偏移量来访问数组中的各个元素。例:当访问arr[1]时,若此时首元素的地址为0x100,则访问的是0x100+1*4个字节假设为0x104的地址中的元素,也就是通过计算偏移量就能实现各个元素的访问。

请添加图片描述

而这也解释了为什么下标(偏移量)是从0开始的。这就好比如往已经写好的公式里填写最后一个元素来完成公式。“首元素地址 + 偏移量 * 数据类型占用字节”,其中首元素地址以及每个元素占用的字节大小已经是知道的,只需要填写偏移量即可。

所以数组下标是从0开始的,其余元素则根据偏移量的大小来访问。

数组的使用

数组既然是为了方便使用,不用再一个个地去声明变量,那自然得可以访问数组中的元素,Java数组是通过下标来访问其中的元素,根据表示的偏移量大小来访问相应地址的所存储的元素。

示例

int[] arr = new int[]{1,2,3};

// 访问数组中的元素
System.out.println(arr[1]); //执行结果: 2
System.out.println(arr[0]); //执行结果: 1
arr[2] = 100;
System.out.println(arr[2]); //执行结果: 100

//获取数组的长度
System.out.println(arr.length); // 执行结果: 3

注意事项

  1. 使用[]可以访问数组中的元素,既能读取数据,也能修改数据。
  2. 使用[]是根据下标来访问数组元素,需要注意的是下标是从0开始计数,且不能超出数组下标的有效范围[0,arr.length-1]
  3. 使用.点操作符可以访问数组的length属性,从而获得数组的长度。

数组越界

int[] arr = new int[]{1,2,3};
System.out.println(arr[3]);		//数组只有三个元素最多支持的下标为arr.length-1即3-1=2,所以数组越界
System.out.println(arr[100]);	//无论你超出多少,只要超出数组下标的有效范围都是造成数组越界

//执行结果
Exception in thread "main" java.lang.ArrayIndexOutOfBoundsException: 100
at Test.main(Test.java:4)

运行程序会抛出java.lang.ArrayIndexOutOfBoundsException异常,这个异常就是数组越界异常,在使用数组时一定要注意数组越界的问题。

数组的遍历

数组的遍历就是将数组中的所有元素都访问一遍,不重复不遗漏,一般是需要搭配循环语句来实现。

int[] arr = new int[]{1,2,3};
for(int i = 0; i < arr.length; i++){
	System.out.println(arr[i]);
}

//执行结果
1
2
3

上述示例是使用for循环来实现数组遍历,当然也可以使用while循环等。有一个for-each循环和其他循环稍微有些不同。

int[] arr = new int[]{1,2,3};
for(int i :arr){
	System.out.println(i);
}

//执行结果
1
2
3

for-each循环它也是去逐个访问数组中的元素,不过后面是将其访问到的元素的数据赋值给前面的变量,上述的例子就是将arr数组中的元素赋值给前面的int类型变量i,通过这种方式也能实现数组的遍历。它能在不使用下标的情况下遍历数组,能够更方便的完成对数组的遍历,可以避免循环条件和更新语句写错。

数组的操作

Java中有个Arrays类(一般以s结尾的类是工具类),其是数组的工具类,为数组的操作提供了很多方法,且方法都是使用static修饰的,直接使用Arrays.method()就可以使用其中的方法。

方法说明
int binarySearch(type[] a, type key)该方法使用二分查找,在a数组中查询是否存在key值,若存在则返回对应key值的索引,否则返回负数。
int binarySearch(type[] a, int fromIndex, int toIndex, type key)此方法和上一个方法类似,但此方法只在a数组中fromIndex到toIndex索引区间中查询。
type[] copyOf(type[] original, int length)该方法将original数组复制为一个新数组,若length值小于original数组的长度,则新数组就是original的前length元素;若length值大于original数组的长度,则新数组前面的元素是original的元素,多出来的部分补充对应数据类型的默认值。
type[] coypOfRange(type[] original, int from, int to)此方法和上一个方法类似,但此方法只复制original数组fromIndex到toIndex索引区间中的元素为新数组,相当于截取数组中的部分元素。
boolean equals(type[] a, type[] b)若a数组和b数组的元素长度相同,并且其中的所有元素一一相同,返回true,否则返回false。
void fill(type[] a, type val)该方法将a数组中的所有元素都赋值为val值。
void fill(type[] a, int fromIndex, int toIndex, type val)此方法和上一个方法类似,但此方法是将a数组中的fromIndex到toIndex索引区间的元素赋值为val值。
void sort(type[] a)该方法对a数组中的数组元素进行排序
void sort(type[] a, int fromIndex, int toIndex)此方法和上一个方法类似,但此方法只对a数组中的fromIndex到toIndex索引区间的元素进行排序。
String toString(type[] a)该方法将一个数组转换为一个字符串

示例

public class Test {
    public static void main(String[] args) {
        int[] a = new int[]{1,2,3,4,5};
        int[] b = new int[]{1,2,4,3,5};
        int[] c = new int[]{1,2,3,4};
        int[] d = new int[]{2,3,4,5,6};
        int[] e = new int[]{1,2,3,4,5};
    }
}

下面示例都是基于上面几个数组来进行的。

二分查询binarySearch

//int binarySearch(type[] a, type key) 在数组中查询元素是否存在,若存在则返回对应索引值

System.out.println(Arrays.binarySearch(a, 1));		//查询a数组中是否存在元素值为1的元素
System.out.println(Arrays.binarySearch(a, 6));		//查询a数组中是否存在元素值为6的元素

//执行结果
0
-6

根据传入的参数的不同,调用的方法也不同,若在其中再传入要查询的区间,则binarySearch则只在区间中查询元素。

//int binarySearch(type[] a, int fromIndex, int toIndex, type key) 在数组a的fromIndex到toIndex区间中查询

System.out.println(Arrays.binarySearch(a, 1, 3, 1));	//查询a数组[1,3]区间中是否存在元素值为1的元素
System.out.println(Arrays.binarySearch(a, 1, 3, 3));	//查询a数组[1,3]区间中是否存在元素值为3的元素

//执行结果
-2
2

根据执行结果可以看出,若在数组中存在要查询的元素,则会返回对应的所有,否则返回负数。

复制数组copyOf

//type[] copyOf(type[] original, int length) 从original数组中复制元素,新数组的长度根据length而定

int[] cp1 = Arrays.copyOf(a, 3);
int[] cp2 = Arrays.copyOf(a, 5);
int[] cp3 = Arrays.copyOf(a, 8);
System.out.println(Arrays.toString(cp1));
System.out.println(Arrays.toString(cp2));
System.out.println(Arrays.toString(cp3));

//执行结果
[1, 2, 3]
[1, 2, 3, 4, 5]
[1, 2, 3, 4, 5, 0, 0, 0]

copyOf方法复制数组为新数组,新数组的长度根据传入的length值来确定,且若length比被复制的数组大则会补充默认值。

复制部分数组copyOfRange

//type[] coypOfRange(type[] original, int from, int to)	从original数组中复制from到to下标的元素,为左闭右开区间[from,to)

int[] cp1 = Arrays.copyOfRange(a, 1, 3);
int[] cp2 = Arrays.copyOfRange(a, 3, 5);
System.out.println(Arrays.toString(cp1));
System.out.println(Arrays.toString(cp2));

//执行结果
[2, 3]
[4, 5]

copyOfRange方法复制部分数组为新数组,复制数组中的从from位置到to位置的元素为新数组,from和to的取值范围为[0,original.length]。

比较数组equals

//boolean equals(type[] a, type[] b)	比较两个数组是否一致

System.out.println(Arrays.equals(a, b));	//两个数组的长度相同,整体元素也相同,但不是对应的元素都想同
System.out.println(Arrays.equals(a, c));	//两个数组的长度不同
System.out.println(Arrays.equals(a, d));	//两个数组的长度相同,但元素不同
System.out.println(Arrays.equals(a, e));	//两个数组的长度相同,整体元素也相同,且对应位置的元素相同

//执行结果
false
false
false
true

equals方法只有当两个数组完全一致(地址不同)的时候,才返回true,否则返回false。

赋值fill

//void fill(type[] a, type val)	给一个数组的所有元素赋值对应的val值

System.out.println(Arrays.toString(a));
Arrays.fill(a,1);
System.out.println(Arrays.toString(a));

//执行结果
[1, 2, 3, 4, 5]
[1, 1, 1, 1, 1]

根据传入的参数的不同,调用的方法也不同,若在其中再传入要赋值的区间,则fill则只会在此区间中进行赋值操作。

//void fill(type[] a, int fromIndex, int toIndex, type val)	给一个数组从from位置到to位置的元素赋值对应的val值,为左闭右开区间[from,to)

System.out.println(Arrays.toString(a));
Arrays.fill(a,1,3,6);
System.out.println(Arrays.toString(a));

//执行结果
[1, 2, 3, 4, 5]
[1, 6, 6, 4, 5]

fill方法为数组中的元素赋值,可以为数组的所有元素赋值,也可以为数组部分区间的元素赋值。

排序sort

//void sort(type[] a) 为数组排序

int[] arr = new int[]{3,6,8,7,4,1,5,2};
Arrays.sort(arr);
System.out.println(Arrays.toString(arr));

//执行结果
[1, 2, 3, 4, 5, 6, 7, 8]

给指定的区间排序。

//void sort(type[] a, int fromIndex, int toIndex) 为数组指定区间的元素排序

int[] arr = new int[]{3,6,8,7,4,1,5,2};
Arrays.sort(arr,2,5);
System.out.println(Arrays.toString(arr));

//执行结果
[3, 6, 4, 7, 8, 1, 5, 2]

sort方法给数组的元素进行排序,可以为整个数组进行排序,也可以为数组的某个区间进行排序。

转换字符串toString

//String toString(type[] a)	将一个数组转换为一个字符串

Arrays.toString(a);

上面方法看到的执行结果很多都是通过toString方法来将其转换为字符串,然后再打印出来方便看到结果。toString方法将数组转换为字符串的格式是前后以方括号括住元素,中间的元素以逗号隔开。[,]

二维数组

二维数组本质上也可以将其看作是一维数组,只不过整个一维数组的所有元素都是一个数组。

基础语法结构

数据类型[][] 数组名 = { 初始化数据 };

数据类型[][] 数组名 = new 数据类型[col][row];	//col和row为常量表达式分别表示二维数组的行数和列数

在声明一个二维数组的时候至少都得要有行数,即数据类型[][] 数组名 = new 数据类型[col][];

代码示例

int[][] arr = {
	{1, 2, 3, 4},
	{5, 6, 7, 8},
	{9, 10, 11, 12}
};

int[][] arr = new int[3][4];

二维数组的用法和一维数组的用法基本一致。同理,还存在"三维数组"、"四维数组"等更加复杂的数组,只不过这些数组的使用频率非常低,以一维数组和二维数组较为常见。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值