每一种高级语言,我们都不可避免的要学习数组的相关知识,今天就跟着笔者来学习一下java的数组创建及相关使用吧,相信你学完一定有所收获!
数组是存储一组相同数据类型的数据集合。
数组本质上就是能让我们批量创建相同类型的变量。
int[] arr={1,2,3,4,5,6,7};
和C语言一样,java中数组的下标也是从0开始,往后依次加1,你可以通过数组的下标来找到数组中的某个元素
静态初始化:
数据类型[ ] 数组名称={初始化数据}
动态初始化:
数据类型[ ] 数组名称=new 数组类型[ ]{初始化数据};
代码如下(示例):
public static void main(String[] args) {
//法一:传统定义数组并初始化
int[] arr={1,2,3};//int[]是一种类型,[]里不能加东西,否则会报错
//这里没有写new,但实际也是一个对象
//法二:用new,定义数组并未初始化
int[] arr2=new int[3];//new是java的关键字,用来实例化java的对象,java的数组也是一个对象
//对象,你可以想象成一个具体的实物
//这句代码效果相当于int[] arr2={0,0,0}
//法三:用new,定义数组并初始化
int[] arr3=new int[]{1,2,3};//这里new int[],[]里也是不能加东西的
//法三这个情况下,编译器也会认为,给了一个长度为3数组,里面存放1,2,3,效果和法一一样
}
法二效果图:
法三效果图:
ps1:静态初始化时,数组元素个数和初始化
数据的格式是一样的
ps2:int[]arr={1,2,3}也可以像C语言一样写成int arr[]={1,2,3},但我们还是建议写int[]arr={1,2,3},这样更方便理解,int[]是整形数组类型
C语言中我们用 sizeof(数组名)/sizeof(数组元素类型)来计算数组的长度,但java中计算数组长度非常简单,我们直接用数组名.length即可
示例如下:
public static void main(String[] args) {
int[] arr={1,2,3,4,5,6,7};
System.out.println(arr.length);
}
这个和C语言是一样的,比如你要访问数组里的第n个元素,直接数组名[n-1]即可,比如现在有1整形数组arr={1,2,3,4,5,6,7},下标分别是
0,1,2,3,4,5,6我现在要访问4这个元素,只要访问数组的第3个下标
public static void main(String[] args) {
int[] arr={1,2,3,4,5,6,7};
System.out.println(arr[3]);
}
运行后打印4
关于数组访问越界:访问下标超出可允许访问范围,比如arr={1,2,3}你可以访问的下标范围是0~2,如果你访问超出这个范围,比如arr[-1],这里会报错,因为你已经越界访问了,给你的那块空间是数组下标0往后到2的空间,你访问前面不属于你的地方,没有人知道当时那块空间在进行什么操作,你突然改变那块空间,可能造成严重后果。
1.一般for循环
public static void main(String[] args) {
int[]arr={1,2,3,4,5,6};
for(int i=0;i<arr.length;i++)
{
System.out.print(arr[i]+" ");
}
}
运行效果如下:
2.增强for循环(for each循环)
写法如下:for(类型名 变量名:数组名)
注意:这里的类型需要与数组元素类型相对应
public static void main(String[] args) {
int[]arr={1,2,3,4,5,6};
for(int x:arr){
//for里面定义一个整形x来接收整形数组里的每一个数
System.out.println(x+" ");
}
}
打印效果如下:
ps:for循环和for each循环的区别
for循环是可以拿到下标的,for each是不可以拿到下标的
比如,你要找的一个数字,然后返回下标,你肯定用普通的for循环。如果只是获取数组里的每个元素,肯定是for each更方便。
3.借助java工具类Arrays
Arrays是java中操作数组的工具类,要借助别人写好的工具类,我们需要打开相关的包import java.util.Arrays;,就像C语言调用一些函数需要#include<头文件>一样
import java.util.Arrays;
public static void main(String[] args) {
int []arr={1,2,3,4,5,6,7};
String ret= Arrays.toString(arr);
//Arrays.toString(arr)是把数组变成一个字符串并返回,
//我们用字符串类型的ret来接收
System.out.println(ret);
//如果你嫌写两行代码麻烦
//直接写System.out.println(Arrays.toString(arr));也可以
}
要学习这块知识,我们需要知道数组的存储方式
public static void main(String[] args) {
int[] array={1,2,3,4,5,6,7};
}
在main函数中,array是一个局部变量,局部变量是放在栈里面的,而{1,2,3,4,5,6,7}则是作为一个对象存放在堆里,那你对象放堆里会有一个地址号,我们这里假设它的地址号是0x789,那么array里面存储的就是0x789。非常类似C语言的指针,也就是说array确实是一个变量,不管它存储的是堆里一个对象的地址。所以我们也称arr为“引用变量”,但毕竟我们学的是java不是C语言,所以我们不讨论指针解引用等问题。
array是个引用变量,引用是用来指向一个对象的,需要注意的是也会有引用变量不指向任何对象,代码如下:
public static void main(String[] args) {
int []arr=null;
System.out.println(arr.length);//运行后会报错——空指针异常
//因为你不指向任何对象嘛,又怎么来谈长度呢
}
public static void hs1(int[]array1) {
array1=new int[]{11,26,13,4,51,61};
}
public static void hs2(int[]array2) {
array2[0]=211;
}
public static void main(String[] args) {
int []array={1,2,3,4,5,6};
System.out.println(Arrays.toString(array));//[1, 2, 3, 4, 5, 6]
hs1(array);
System.out.println(Arrays.toString(array));//[1, 2, 3, 4, 5, 6]
hs2(array);
System.out.println(Arrays.toString(array));//[211, 2, 3, 4, 5, 6]
}
我们假设array指向的对象地址为0x123
关于hs1,我们进入hs1这个方法后,array把它指向的对象地址传给array1,array1里保存0x123,也就说刚进去hs1方法时,array1也指向{1,2,3,4,5,6}这个对象
但是后面 array1=new int[]{11,26,13,4,51,61};我们在堆里new了一个新的对象赋值给array1,我们假设新对象地址0x456,这时,array1就指向新的对象了
需要注意的是,这里的array1是形参,它并没有影响到实参array,你第二次打印的是实参array,所以还是打印[1, 2, 3, 4, 5, 6]
关于hs2,我们进入hs2之后,array把它指向的地址传给array2,也就是array2存放0x123,然后我们通过array2这个引用变量,找到它指向对象的下标为0的值1并将值1修改为899
hs2和hs1的区别是什么呢?hs2是通过形参的引用来改变引用变量所指向对象的值,hs1则是改变了形参所指向的对象,两者有本质区别
注意:一个引用只能有一个对象,不然就是"海王",海王是要被系统警告的哈
举个代码的例子:
public static void main(String[] args) {
int []arr=new int[]{1,2,3,4,5};
arr=new int[]{1};
arr=new int[]{2};
arr=new int[]{3};
System.out.println(Arrays.toString(arr));//打印[3]
}
说个大白话就是,你arr现在是一个小伙子,这个小伙子一开始有个数组对象{1,2,3,4,5},但是他们分手了;他又找了另一个数组对象{1},又分手了;后续又找了数组对象{2},分手了。最后他找到了真爱数组对象{3}。你能说他有错吗?不能,他又没同时和多个人谈恋爱,这不是很正常的吗?这个例子也能侧面告诉我们为啥引用变量可以找到他指向的对象,小伙子有他女朋友的联系方式这很正常吧。
ps:引用变量不一定在栈上
一个变量在不在栈上,是由你变量的性质决定的,如果是一个局部变量、实例成员变量就不一定在栈上了,但它们都可以引用变量。就好比不管你出生在哪个地方,你都有可能获得对象,不是说只有一个地方才有权利获得对象。
代码示例:写一个方法,将数组内元素全部*2
法一:
public static void func(int[]array) {
for(int i=0;i<array.length;i++)
{
array[i]*=2;
}
}
public static void main(String[] args) {
int []arr={1,2,3};
func(arr);
System.out.println(Arrays.toString(arr));
}
引用变量arr指向对象{1,2,3},调用func方法,我们把实参arr保存的地址交给形参array,也就是说array也可以指向对象{1,2,3}。然后我们通过array下标实现对象的修改。
但是这样的扩大二倍是在原数组的基础上扩大二倍,也就说原数组被改变了
法二:
public static int[] func2(int []arr) {
int []ret=new int[arr.length];
for(int i=0;i<arr.length;i++)
{
ret[i]=2*arr[i];
}
return ret;
}
public static void main(String[] args) {
int []arr={1,2,3};
int []brr=func2(arr);
System.out.println(Arrays.toString(brr));
}
引用变量arr指向一个对象{1,2,3},我们调用方法func2,对象{1,2,3}的地址交给了形参arr,然后我们new一个和arr相同大小的对象并交给ret,然后用arr里的数*2赋给ret数组,然后返回ret即可。
示意图如下:
这样就不会改变原数组的值。
public static String myToString(int[] arr) {
if(arr==null)
{
return null;
//防止传过来的引用变量没有任何对象,
//那也就没有后续的.length说法了
}
String str="[";
for(int i=0;i<arr.length;i++)
{
str=str+arr[i]+",";
}
str=str+"]";
return str;
}
public static void main(String[] args) {
int []arr={1,2,3};
System.out.println(myToString(arr));
}
二维数组本质上也是一维数组,只不过每个元素又是一个一维数组。
基本语法:
数据类型[][]数组名称=new 数据类型[行数][列数]{初始化数据};
三种创建方法示例如下:
public static void main(String[] args) {
//法一
int[][]arr={{1,2,3},{4,5,6}};
//java中不允许int[][]这个[][]里加数字,这是一种类型
//另外,你不能直接写{1,2,3,2,3},必须你手动进行分行(加括号)
//法二
int[][]brr=new int[][]{{1,2,3},{4,5,6}};
//这样的创建方式也可以,但和法一一样,new int[][],[][]里不能加指定数字
//法三
int[][]crr=new int[2][3];
//如果不进行初始化只是new一个对象可以new int[2][3],
// [][]里可以加数字(不然不知道你要开辟多大空间)
}
打印二维数组的每个元素
虽然说是二维数组,但和C语言一样,n维数组的本质都是1维数组,只不过每个一位数组里的元素都是数组,示意图如下:
public static void main(String[] args) {
int[][]arr={{1,2,3},{4,5,6}};
System.out.println(arr.length);
//打印2,说明arr这个二维数组里存放2个引用变量,分别指向两个对象
//也印证了上图,二维数组arr中是保存了2个引用变量
for(int i=0;i< arr.length;i++)
//因为大多数情况int[][]是不告诉你有多少行多少列的,
//arr.length可以快速计算出行数
{
for(int j=0;j<arr[i].length;j++)
//arr[i]进去arr里,也就是arr里的一个引用变量,
// 然后引用变量.length计算出它指向对象的长度,也就是列数
{
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
public static void main(String[] args) {
int[][]arr={{1,2,3},{4,5,6}};
for(int[]ret:arr)//arr是一个一维数组,里存放2个引用变量,我们用一维数组ret来接受
{
for(int x:ret)//ret是一个一维数组,我们用x来接受数组里的数据
{
System.out.print(x+" ");
}
System.out.println();
}
}
public static void main(String[] args) {
int[][]arr={{1,2,3},{4,5,6}};
System.out.println(Arrays.deepToString(arr));
}