什么是数组
数组:可以看成是相同类型元素的一个集合。在内存中是一段连续的空间。
- 数组中存放的元素其类型相同
- 数组的空间是连在一起的
- 每个空间有自己的编号,起始位置的编号为0,即数组的下标。
数组的创建及初始化
T[] 数组名 = new T[N];
T:表示数组中存放元素的类型
T[]:表示数组的类型
N:表示数组的长度
常见的java数组定义有三种方式
//数组
public class helloworld{
public static void main(String[] args) {
//java定义数组的第一种方式
int[] arr1 = {1,2,3,4,5,6};
//java定义数组的第二种方式
int[] arr2 = new int[]{1,2,3,4,5,6};
//java定义数组的第三种方式
int[] arr3 = new int[10];//d动态初始化
}
}
int[] arr1 = {1,2,3,4,5,6};
与
int[] arr2 = new int[]{1,2,3,4,5,6};
他们都是静态初始化,都是在内存中开辟了六个整型变量的存储空间(连续),并且初始为123456
new是一个java的关键字,一般通过new来实现实例化对象。java中的数组其实就是一个对象。
最后一种只是开辟了一块内存空间(10个整型变量)又名动态初始化。系统默认数组元素没有初始化之前的值为0。
//java定义数组的非法定义
int[] arr4 = new int[10]{1,2,3,4}//非法定义
java中 后面的[]中的数字与初始化的123456等是不能同时存在的,两者只能存在一个。
初始化也可以分成两步
此外一开始不初始化,后面初始化也可以
int[] arr5 ;
arr5 = new int[]{1,2,3 4};//静态初始化分成两步
int[] arr6;
arr6 = new int[10];//动态初始化分成两步
分成两步是注意,数组类型是不可以省略的。
所以这样是非法的
int[] arr6;
arr6 = {1,2,3,4,5}//非法初始化
int[] arr7 = new int[10];
arr = {1,2,3,4,5,6,7,8,9,10}//非法初始化
前面说了,int型数组没有手动初始化,系统会默认初始化为0.此外、其他数据类型也会系统也会初始化成特定的类型。
如果数组中存储类型是引用类型,默认值为NULL;
实际上之所以数组和其他数据类型不一样,创建时需要用到new 而像int char等都不需要用到,这是因为数组是引用类型,其实字符串类型也是引用类型,但是字符串创建的时候可以直接写 String str = “abcde”,其实这是简写,真正的书写是String str =new String “abcde”.
数组的使用
数组在内存中是一段连续的空间,空间的编号都是从0开始的,依次递增,该编号称为数组的下标,数组可以通过下标访问其任意位置的元素。
int[]array = new int[]{10, 20, 30, 40, 50};
System.out.println(array[0]);
System.out.println(array[1]);
System.out.println(array[2]);
System.out.println(array[3]);
System.out.println(array[4]);
// 也可以通过[]对数组中的元素进行修改
array[0] = 100;
System.out.println(array[0]);
- 数组是一段连续的内存空间,因此支持随机访问,即通过下标访问快速访问数组中任意位置的元素
- 下标从0开始,介于[0, N)之间不包含N,N为元素个数,不能越界,否则会报出下标越界异常
在数组中可以通过 数组对象.length 来获取数组的长度
public class helloworld{
public static void main(String[] args) {
int[] arr1 = new int[4];
System.out.println(arr1.length);
}
}
遍历数组
可以使用for循环
int[]array = new int[]{10, 20, 30, 40, 50};
for(int i = 0; i < 5; i++){
System.out.println(array[i]);
}
也可以使用for-each
public class helloworld{
public static void main(String[] args) {
int[] arr1 = new int[4];
System.out.println(arr1.length);
for(int x:arr1){//元素类型 x : 数组名
System.out.println(x);//x也可以改成y、z等
}
}
}
此外,还可以导入java里面的array包,调用这个包里面的方法
如果单纯只是打印数组里面的内容,可以使用toString方法
import java.util.Arrays;//java类里面的Arrays
public class helloworld {
public static void main(String[] args) {
int[] arr1 = new int[4];
System.out.println(arr1.length);
// for (int x : arr1) {
// System.out.println(x);//x也可以改成y、z等
System.out.println(Arrays.toString(arr1));
}
}
数组是引用类型
java代码是运行在jvm虚拟机中,虚拟机中也是要对内存你进行划分的,可以划分成:本地方法栈、堆、程序计数器、方法栈、虚拟机栈
我们平时说栈实际是虚拟机栈。
从底层来时,系统运行int[] array = new int[] {1,2,3,4}这段代码的时候,会先堆区创建四个整型变量(16个字节)的连续空间用来存1234,然后在栈区(虚拟机栈)中创建一个array变量,并存上 1234的首地址,所以其实这玩意和C里面的指针很像。所以这个引用类型应该也是四个字节
public class helloworld {
public static void main(String[] args) {
int[] arr1 = new int[]{1,2,3,4};
System.out.println(arr1);
}
}
如果将引用变量赋值为null,那么就是说这个arr1指向空
import java.util.Arrays;//java类里面的Arrays
public class helloworld {
public static void main(String[] args) {
int[] arr1 ;
arr1 = null;
System.out.println(arr1);//打印出来是null
System.out.println(arr1[0]);//报错
}
}
注意的是
C语言NULL可能指向的是0号地址空间,这个地址空间是受保护的,是不可以被访问的,所以会报错,但是java里面null没有和0号地址关联。
JAVA中NULL只表示不指向任何对象。
数组传参
//SE.7.01:00:00
先来看这个代码
import java.util.Arrays;
public class helloworld {
public static void fun_1(int[] arr) {
arr = new int[]{10, 11, 12};
System.out.println(Arrays.toString(arr));//结果是【10,11,12】
}
public static void fun_2(int[] arr) {
arr[0] = 188;
}
public static void main(String[] args) {
int[] arr1 = new int[]{1, 2, 3, 4, 5};
int[] arr2 = new int[]{6, 7, 8, 9, 10};
fun_1(arr1);
fun_2(arr2);
System.out.println(Arrays.toString(arr1));//结果依旧是盘【1,2,3,4,5】
System.out.println(Arrays.toString(arr2));//结果是【188,7,8,9,10】
}
}
我们把整个过程顺一遍,首先在系统的堆区开辟两片连续内存空间,一片存1,2,3,4,5,一片存6,7,8,9,10。因为是在main函数内,所以arr1和arr2都是局部变量。所以是在栈区创建两个指向整型数组的引用类型变量arr1,arr2分别指向前面两块空间的首地址。假设arr1存的是0x12345678
arr2存的是0x45678912
现在执行fun1,arr还是局部变量,所以还是创建在栈区,然后将arr1的内容传给arr,所以arr的内容是0x12345678,然后执行new int[]{10, 11, 12};
这一句,系统在堆区开辟一块空间存的是10,11,12,假设首地址是0x24681012,然后将arr指向这片空间,此时就要注意了,这之后,arr的内容不再是0x12345678,而是新的0x24681012.所以后面打印时,打印的是10,11,12.然后fun1执行结束,栈区里面的arr出栈,也就是局部变量销毁,同时堆区里面的0x12345678这片空间释放。
但是执行fun_2时,因为堆区并没有开辟新的空间,所以arr还是存的是0x45678912,所以arr[0]赋值188就是原本0x45678912这里的第一个元素改为188,所以打印时的元素会是188,7,8,9,10
所以实际上,当数组作为参数传递时,还是按值去传递的
当形参修改指向时: arr = new int[]{10, 11, 12};
只会影响形参指向,对实参没有任何影响
当形参修改指向对象的值时,实参才会受到影响arr[0] = 188;
数组作为返回值
SE.07.01:31:37
import java.util.Arrays;
public class helloworld {
public static int[] fun_double(int[] arr) {
int i = 0;
for (i = 0; i < arr.length; i++) {
arr[i] = arr[i] * 2;
}
return arr;
}
public static void main(String[] args) {
int[] arr1 = new int[]{1, 2, 3, 4, 5};
int[] ret = fun_double(arr1);
System.out.println(Arrays.toString(ret));
}
}
但是下面这个代码要注意
import java.util.Arrays;
public class helloworld {
public static int[] fun_double(int[] arr) {
int i = 0;
for (i = 0; i < arr.length; i++) {
arr[i] = arr[i] * 2;//这里对实参也有影响
}
return arr;
}
public static void main(String[] args) {
int[] arr1 = new int[]{1, 2, 3, 4, 5};
int[] ret = fun_double(arr1);
System.out.println(Arrays.toString(ret));//打印出来是[2, 4, 6, 8, 10]
System.out.println(Arrays.toString(arr1));//打印出来也是[2, 4, 6, 8, 10]
}
}