数组的定义与使用
数组的基本用法
1.1 什么是数组
数组本质上就是让我们能“批量”创建想同类型的变量
注意事项:在Java中,数组包含的只能是相同类型
1.2 创建数组
基本语法:
//动态初始化
数据类型[] 数组名称 = new 数据类型 [长度];
数据类型[] 数组名称 = new 数据类型 [长度]{初始化数据};
//静态初始化
数据类型[] 数组名称 = {初始化数据};
加new 都是动态初始化
代码示例
int[] arr = new int[3];
int[] arr = {1,2,3};
int[] arr = new int[3]{1,2,3};
注意:静态初始化时,数组元素个数和初始化数据的格式是一致的
1.3 数组的使用
代码示例:获取长度和访问元素
int[] arr = {1,2,3};
//获取数组长度
System.out.println("length:"+arr.length); //执行结果:3
//访问数组元素
System.out.println(arr[0]); //执行结果:2
System.out.println(arr[1]); //执行结果:1
arr[2]=100;
System.out.println(arr[2]); //执行结果:100
注意事项
1.数组下标是从0开始的
2.使用[ ]既能读取数据也能修改数据
3.数组下标若超过length-1,会发生数组越界
下标越界会抛出异常(数组越界异常):java.lang.ArrayIndexOutOfBoundsException:
4.数组中length不是方法,是属性
5.当定义数组后,没有初始化,默认值为0
如果数组为引用类型时,默认值为null
6. null:是所有引用类型的初始值
代码示例:打印数组
code1
int[] arr = {1,2,3};
for(int i=0;i<arr.length;i++) {
System.out.println(arr[i]);
}
//执行结果:
1
2
3
code2 for——each
int[] arr={1,2,3};
for (int x:arr ) {
System.out.print(x+" ");
}
//执行结果:1 2 3
for循环和foreach循环有什么区别?
- foreach 不能够用下标去访问
打印数组: Arrays.toString(数组名)
将数组以字符串的形式输出
2.数组作为方法的参数
2.1基本用法
代码示例:
public static void print(int[] array) {
for (int x:array) {
System.out.print(x+" ");
}
}
public static void main(String[] args) {
int[] arr = {1, 2, 3};
print(arr);
}
//运行结果: 1 2 3
在这个代码中,int[ ] arr是实参,int[ ] array是形参
如果要获取长度,使用arr.length
引用类型
代码示例
public static int print(int b) {
b=20;
return b;
}
public static void main(String[] args) {
int a=10;
print(a);
System.out.println(a);
}
//执行结果: 10
修改形参b的值,不影响实参a的值
参数传数组类型:
public static int[] print(int[] array) {
array[0]=99;
return array;
}
public static void main(String[] args) {
int[] a=new int[]{1};
int[] ret=print(a);
System.out.println(a[0]);
}
//执行结果: 99
在函数内部修改数组内容,函数外部也发生改变
此时数组arr是一个“引用”,传参的时候按照引用传参
针对int[] arr=new int []{1,2,3};
这样的代码,内存布局如下:
接下来执行int[] arr=new int []{1,2,3};
相当于又创建了一个int[]
的变量,这个变量是一个引用类型,里面保存的是arr的首元素地址
接下来我们进行传参,相当于int[] array=arr;
:
接下来就是修改arr[0],此时是根据0x100
地址找到对应的位置,将值改为99
此时0x100
地址的值改为99,那么根据实参arr来获取数组内容arr[0]
,本质上也是获取0x100
的地址,也是99
总结:所谓的“引用”本质上只是存了一个地址,Java将数组设定为引用类型,这样的话,后面进行数组参数传参,其实只是将数组的首元素地址传入函数形参中
2.3初识JVM
- 程序计数器 (PC Register): 只是一个很小的空间, 保存下一条执行的指令的地址. 虚拟机栈(JVM Stack): 重点是存储局部变量表(当然也有其他信息). 我们刚才创建的 int[] arr 这样的存储地址 的引用就是在这里保存.
- 本地方法栈(Native Method Stack): 本地方法栈与虚拟机栈的作用类似. 只不过保存的内容是Native方法的局部 变量. 在有些版本的 JVM 实现中(例如HotSpot), 本地方法栈和虚拟机栈是一起的.
- 堆(Heap):
JVM所管理的最大内存区域. 使用 new 创建的对象都是在堆上保存 (例如前面的 new int[]{1, 2,3} ) . - 方法区(Method Area): 用于存储已被虚拟机加载的类信息、常量、静态变量、即时编译器编译后的代码等数据. 方法编译出的的字节码就是保存在这个区域.
- 运行时常量池(Runtime Constant Pool): 是方法区的一部分,存放字面量与符号引用.
Native 方法: JVM 是一个基于 C++ 实现的程序. 在 Java 程序执行过程中, 本质上也需要调用 C++
提供的一些函数进行和操作 系统底层进行一些交互. 因此在 Java 开发中也会调用到一些 C++ 实现的函数. 这里的 Native
方法就是指这些 C++ 实现的, 再由 Java 来调用的函数.
3.数组作为方法的返回值
code1:
public static int[] mul(int[] array) {
int[] a=new int[array.length];
for (int i = 0; i < array.length; i++) {
a[i]=array[i]*2;
}
return a;
}
public static void main(String[] args) {
int[] arr = {1, 2, 3, 4};
int[] ret=mul(arr);
System.out.println(Arrays.toString(ret));
}
//运行结果:
[2,4,6,8]
数组的拷贝
数组拷贝:
1.System.arraycopy(原数组名称,原数组开始点,目标数组名称,目标数组开始点,拷贝长度):被native所修饰的方法
2.Arrays.copyOf(原数组,目标数组,长度):方法内部调用System.arraycopy()
3.数组名.clone(); 数组名:拷贝的数组-》原数组
4.for();
- 数组当中是简单类型/内置类型,那就是深拷贝
- 如果是引用类型,那就是浅拷贝 如果是两个引用
- 同时指向一个对象,那么通过一个引用,修改当前对象的值后,那么另一个引用也会受到影响,这种拷贝叫浅拷贝。
二分查找:Arrays.binarySearch();
排序:Arrays.sort(array);
打印二维数组:Arrays.deepToString();
两数组是否相同:equals 判断两个数组是不是相同
填充:Arrays.fill(array,9) ; 会将数组全部填充为9
Arrays.fill(array,2,7,9);将数字[2,7)填充为9
对一个数开根号:Math.sqrt();
引用类型比较内容是否相同用: .equals();
4.二维数组
code:
public static void main(String[] args) {
int[][] arr=new int[][]{{1,2},{3,4},{5,6}};
for (int i = 0; i <arr.length ; i++) {
for (int j = 0; j <arr[i].length ; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
//执行结果:
1 2
3 4
5 6