下面简单介绍一下java中数组的定义和使用。我觉得挺好的。我现在就分享给你,给你一个参考。来和边肖一起看看吧。
:
目录
1.数组1的基本用法。什么是数组2。创建数组3。使用数组2。数据作为方法参数1。基本用法2。了解参考类型3。知否null 4。划分JVM内存区域5。数组作为方法6的返回值。数组4的地址。阵列练习1。数组转换为字符串2。数组副本5。二维数组1。二维数组的语法2。
一、数组的基本用法
1.什么是数组
数组本质上允许我们“批量”创建相同类型的变量。
如果我们需要创建多个同类型的变量,不可能手工逐个创建,比如:int n=10int m=20int y=30等等,所以数组可以帮助我们批量创建相同类型的数据。
注意:在Java中,数组中包含的变量必须是同一类型。
2.创建数组
基本语法:
//动态初始化
数据类型数组名[]=新数据类型[]{初始化数据};
//静态初始化
Type []数据数组名称={初始化数据};
//不要初始化
Type [] array name=新数据类型[要创建的数组长度];
代码示例:
int[] arr=new int[]{1,2,3 };
int[] arr={1,2,3 };
int[]arr=new int[3];
注意:静态初始化时,数组元素的个数与初始化数据的格式一致。
虽然我们也可以用:int arr[]={1,2,3 };但还是更推荐用int[] arr的形式来写。Int和[]是一个整体。
3.数组的使用
int[] arr={1,2,3 };
//获取数组长度
system . out . println(' length:' arr . length ');//执行结果:3
//访问数组中的元素
system . out . println(arr[1]);//执行结果:2
system . out . println(arr[0]);//执行结果:1
arr[2]=100;
system . out . println(arr[2]);//执行结果:100
1.数组的长度可以通过使用arr.length获得,这个操作是一个成员访问操作符。在面向对象的后面会经常用到。
2.使用[]通过下标提取数组元素。需要注意的是下标从0开始计数。
3.使用[]操作不仅可以读取数据,还可以修改数据。
4.下标访问操作不能超出有效范围[0,长度-1]。如果是这样,将发生下标越界异常。
代码示例: 下标越界
int[] arr={1,2,3 };
system . out . println(arr[100]);
//执行结果
线程“main”Java . lang . arrayindexoutofboundsexception中的异常:Test.main处的100(test . Java:4)
引发了Java . lang . arrayindexoutofboundsexception异常。使用数组时,必须给它加下标以防止越界。
代码示例:遍历数组
所谓“遍历”是指将数组中的所有元素访问一次,不遗漏任何东西,通常使用循环语句。
int[] arr={1,2,3 };for(int I=0;长度;I){ system . out . println(arr[I]);
}
//执行结果
一个
2
三
代码示例: 使用 for-each 遍历数组
int[] arr={1,2,3 };
for (int x : arr) {
system . out . println(x);
}
//执行结果
一个
2
三
For-each是For循环的另一种使用方式,可以更方便地完成数组的遍历,避免循环条件和update语句的错误写入。
另一种方式使用for-each,它只能遍历数组中的所有数据,X可以在遍历时读取数组中对应下标的数据。
代码示例:
int[] arr={1,2,3,4,2 };
int count=0;
for (int x:arr) {
if(x==2) {
数数;
}
}
system . out . println(count);//结果是2
二、数据作为方法参数
1.基本用法
代码示例: 打印数组内容
公共静态void main(String[] args) {
int[] arr={1,2,3 };
打印数组(arr);
}
public static void print array(int[]a){
for (int x : a) {
system . out . println(x);
}
}
//执行结果
一个
2
三
注意:
1.int[] a是函数的形参,int[] arr是函数的实参。
2.如果需要获得数组长度,也可以使用. length
2.理解引用类型
代码示例1 参数传内置类型
公共静态void main(String[] args) {
int num=0;
func(数字);
system . out . println(' num=' num);
}
公共静态void函数(int x) {
x=10
system . out . println(' x=' x);
}
//执行结果
x=10
数量=0
代码示例2 参数传数组类型
公共静态void main(String[] args) {
int[] arr={1,2,3 };
func(arr);
system . out . println(' arr[0]=' arr[0]);
}
public static void func(int[] a) {
a[0]=10;
system . out . println(' a[0]=' a[0]);
}
//执行结果
a[0]=10
arr[0]=10
我们发现在方法内部修改数组的内容也会改变方法的外部。
这时数组名arr就是一个“引用”。传递参数时,参数是根据引用传递的。引用类型类似于C语言中的指针,但有许多不同之处。
引用可以理解为:创建一个引用就相当于创建了一个很小的变量,这个变量保存了一个表示内存中地址的整数。
对于int[] arr=new int[]{1,2,3}这样的代码,内存布局如下:
当我们创建new int[]{1,2,3}时,相当于创建了一个内存空间来存放三个int。接下来,执行int[] arr=new int[]{1,2,3}相当于创建另一个int[]变量,这个变量是一个引用类型,只保存一个整数(数组的起始内存地址)。
3.接下来传递参数等价于int[] a=arr,内存布局如图所示:
4. 接下来我们修改 a[0] , 此时是根据 0x100 这样的地址找到对应的内存位置, 将值改成 100 。内存布局如图:
因为创建arr时int[] arr和int[] a所指向的内存空间都是新对象(三个整数数据),虽然其中一个数据发生了变化,但是arr和a所指向的空间保持不变,所以arr和a都会随着对象的变化而变化,这就是引用。
总结: 所谓的“引用”本质上只是存储一个地址,Java将数组设置为引用类型。在这种情况下,数组的后续参数传递实际上只是将数组的地址传入函数参数,可以避免复制整个数组(数组可能会更长,所以复制开销会很高)
3.认识null
Null在Java中是“空引用”的意思,是无效引用。
代码示例:
int[]arr=null;
system . out . println(arr[0]);
//执行结果
线程“main”中的异常Java . lang . nullpointerexception at test . main(test . Java:6)
null的作用类似于C语言中的NULL(空指针),表示无效的内存位置。因此,你不能读写这个内存。一旦尝试读写,就会抛出NullPointerException。
注意:Java中没有约定null和地址0的内存有什么关系。即使打印出来,打印出来的结果也是null。
4.JVM内存区域划分
学习Java之初,我们知道JVM的全称是Java虚拟机,可以运行Java编译的字节码文件。实际上运行时,它要打开堆栈帧,在堆中分配内存等等,于是就有了JVM的内存布局。
JVM的内存布局可以分为六个区域:程序计数器、JVM虚拟机栈、JVM本地方法栈、方法区、堆区和运行时常量池。它们之间的内存布局:
程序计数器(PC寄存器):它只是一个小空间,用来保存下一条执行指令的地址。
虚拟机栈:重点是存储局部变量表(当然还有其他信息)。我们刚刚创建的int[] arr之类的存储地址的引用保存在这里。
Native Method Stack:native Method Stack的功能和虚拟机Stack类似,只是存储的内容是native Method的局部变量,运行速度非常快。在某些版本的JVM实现中(比如HotSpot),本机方法栈和虚拟机栈是在一起的。
堆:JVM管理的最大内存区域。用new创建的所有对象都保存在堆上(例如,前面的new int[]{1,2,3})
方法区(Method Area):用于存储已经被虚拟机加载的类信息、常量、静态变量、实时编译器编译的代码等数据。由方法编译的字节存储在这个区域。
运行时常量池:方法区的一部分,存储文字量(字符串常量)和符号引用(注意从JDK1.7开始,运行时常量池在堆上)。
本机方法:
JVM是基于C的程序,在Java程序执行过程中,调用C提供的一些函数与操作系统底层进行交互是必不可少的。所以C实现的一些功能在Java开发中会被调用。
这里的原生方法指的是这些由C实现,然后由Java调用的函数。
这里我们只知道JVM的内存布局,重点是JVM虚拟机栈中存储了什么,栈上存储了多少。
局部变量和引用存储在堆栈上,新对象存储在堆上。
堆空间很大,栈空间相对较小。
堆栈由整个JVM共享,每个线程有一个堆栈(一个Java程序中可能有多个堆栈)。
5.数组作为方法的返回值
代码示例:编写一个方法使数组中的每个元素* 2
//直接修改原数组
类别测试{
公共静态void main(String[] args) {
int[] arr={1,2,3 };
transform(arr);
打印数组(arr);
}
public static void print array(int[]arr){
for(int I=0;长度;i ) {
system . out . println(arr[I]);
}
}
公共静态void转换(int[] arr) {
for(int I=0;长度;i ) {
arr[I]=arr[I]* 2;
}
}
}
这段代码是可行的,但是它破坏了原始数组。有时候我们不想破坏原来的数组,就需要在方法内部创建一个新的数组,由方法返回。在Java中,一个方法可以返回一个数组。
//返回新的数组类Test {
公共静态void main(String[] args) {
int[] arr={1,2,3 };
int[]output=transform(arr);
printArray(输出);
}
public static void print array(int[]arr){
for(int I=0;长度;i ) {
system . out . println(arr[I]);
}
}
公共静态int[] transform(int[] arr) {
int[]ret=new int[arr . length];
for(int I=0;长度;i ) {
ret[I]=arr[I]* 2;
}
返回ret
}
}
这样,原来的阵列就不会被破坏。
另外,由于数组是引用类型,所以返回时只将数组的第一个地址返回给函数调用方,不复制数组的内容,所以效率更高。
6.关于数组的地址
在Java中,为了维护数据的安全性,我们不能获取数组的地址(已经做了特殊处理)。如果你想打印数组的地址,我们会发现下面的结果:
为什么打印结果是这样的?
进入println的源代码,可以看到println中有一个专门处理地址的方法:
它根据哈希值处理数组的地址,但数组的地址仍然是唯一的。
四、数组练习
1.数组转字符串
代码示例:
导入java.util.Arrays
int[] arr={1,2,3,4,5,6 };
string new arr=arrays . tostring(arr);
system . out . println(new arr);
//执行结果
[1, 2, 3, 4, 5, 6]
以后用这种方法打印数组更方便。
Java提供了java.util.Arrays包,其中包含了一些操作数组的常用方法。
2.数组拷贝
代码示例:
导入java.util.Arrays
int[] arr={1,2,3,4,5,6 };
int[] newArr=Arrays.copyOf(arr,arr . length);
system . out . println(' newArr:' arrays . tostring(newArr));
arr[0]=10;
system . out . println(' arr:' arrays . tostring(arr));system . out . println(' newArr:' arrays . tostring(newArr));
//复制一个范围。
int[]new arr=arrays . copyofrage(arr,2,4);
system . out . println(' new arr 2:' arrays . tostring(new arr 2));
注意:与newArr=arr的赋值相比,copyOf是对数组进行深度复制,即创建另一个数组对象,将原数组中的所有元素复制到新数组中。因此,修改原始数组不会影响新数组。而轻拷贝是拷贝时原始阵列。
实际上,复制数组有四种方法。
1.for循环逐个复制。
2.调用Arrays包中的类来实现它。
3.System.arraycopy,它可以设置复制开始和结束的位置(最快的复制)
4.数组名。克隆()
虽然这四种复制数组的方法都有深度复制的特点(复制到一个新的数组中,改变新数组中的数据,原数组不会改变)。不过都是处理简单类型的,面试的时候都可以作为浅抄来回答。
代码示例:
for循环拷贝:
int[] arr={1,2,3,4 };
int[]a=new int[4];
for(int I=0;iarr .长度;i ) {
a[I]=arr[I];
}
for (int x:a) {
system . out . println(x);
}
System.arraycopy拷贝:
int[] arr={1,2,3,4 };
int[]a=new int[arr . length];
System.arraycopy(arr,0,a,0,arr . length);
system . out . println(arrays . tostring(a));
数组名.clone拷贝:
int[] arr={1,2,3,4 };
int[]a=new int[arr . length];
a=arr . clone();
system . out . println(arrays . tostring(a));
五、二维数组
1.二维数组的语法
二维数组本质上是一维数组,只是每个元素都是一维数组。
基本语法:
数据类型数组名[] []=新数据类型[行数] [列数]{初始化数据};
代码示例:
int[][] arr={ {1,2,3,4},{5,6,7,8},{9,10,11,12 } };
for(int row=0;行排列长度;row ) {
for(int col=0;列排列[行]。长度;col ) {
System.out.printf('%d\t ',arr[row][col]);
}
system . out . println(');
}
//执行结果
1 2 3
4 5 6
7 8 9
10 11 12
注意:Java中的二维数组只能省略列,不能省略行,否则编译器会报错。
二维数组可以定制,那么怎么定制呢?
代码示例:
int[][]arr=new int[2][];
arr[0]=new int[]{1,2,3 };
arr[1]=new int[]{4,5 };
for (int[] a:arr) {
for (int x:a) {
system . out . print(x ' ');
}
system . out . println();
}
运行结果:
2.二维数组的结构
这里我们分析一下数组int[2][3]的结构。类似地,当创建新的二维数组对象时,它们被存储在堆区中,而数组名(变量)是引用并存储在堆区中。
注意:在Java中,要获取二维数组的行号,实际上是一维数组,所以上面打印二维数组的代码中获取行号的方式是arr.length,是一维数组,所以获取二维数组每一列的方式是arr[row]。长度
3.用for-each遍历二维数组
使用foreach遍历二维数组:
代码示例:
int[][] arr={{1,2,3},{2,3,4 } };
for (int[] tmp:arr) {
for (int x:tmp) {
system . out . print(x ' ');
}
system . out . println();
}
总结
本文到此为止。希望能帮到你,也希望你能多关注我们的更多内容!
郑重声明:本文由网友发布,不代表盛行IT的观点,版权归原作者所有,仅为传播更多信息之目的,如有侵权请联系,我们将第一时间修改或删除,多谢。