三种定义方式:
public static void main1(String[] args) {
int[] array1 = {1, 2, 3, 4};
int[] array2 = new int[]{1, 2, 3, 4}; //前两者是直接进行了初始化
int[] array3 = new int[10]; //只在堆上分配了引用对象所指向地址的空间,没有初始化
}
以上三种方式,其实array1 和 array2 都是一样的,array1 是 array2的简写,所以说我们的数组是需要new出来的!!!
我们都知道数组在Java中是引用数据类型,为什么呢?看下面
如果说一个基本的数据类型 比如直接就是 int a = 10,此时是在栈上开辟的空间,
而我们的数组是需要new出来的,而new出来的都会在堆上开辟空间。所以数组是引用数据类型!
所以说: 每创建一个数组,都会在栈和堆上开辟相应的空间,然后栈上的引用变量(比如下面的array1-->0x123)存的地址和堆上的地址(0x123)相同,所以通过array1就可以对数组进行操作。
看图片
先来看一组代码:
public static void main2(String[] args) {
//两个数组指向一个对象,然后选择一个进行对对象的修改
int[] array1 = {1,2,3,4};
array1[0] = 99;
int[] array2 = array1; //此时array2 也指向 array1指向的引用地址;
array2[0] = 100; //array1指向的数组值被修改了
System.out.println(Arrays.toString(array1));//{ 100,2,3,4}
System.out.println(Arrays.toString(array2));//{ 100,2,3,4}
}
以上代码中,最重要的是第三行代码,此时array2数组接收的是array1数组所指向对象的地址,也就是说代码执行到现在,array1 和 array2 都指向同一个对象,也就是{ 1 , 2 , 3 , 4 },所以运行结果都一样。看图:
如果明白了看下面代码:
public static void main(String[] args) {
//数组回收
int[] array1 = {1,2,3,4};
int[] array2 = {11,22,33,44};
array1 = array2;// array1 也指向了 array2指向的地址 ,此时array1原来指向的数组被回收
array1[0] = 100;
System.out.println(Arrays.toString(array1));//100 22 33 44
System.out.println(Arrays.toString(array2));// 100 22 33 44
}
此时代码输出如上图,最重要的也是第三行代码,此时array1接受了array2对象的地址,也就是两个引用同时指向了一个对象!所以此时array1 和 array2 都指向了 array2对象,也就是堆上的{ 11,22,33,44},所以array1修改值就会改变数组的值了。下面是图解:
public static void func1(int[] array1) {
array1 = new int[]{15,16,17};
}
public static void func2(int[] array2) {
array2[0] = 99;
}
public static void main(String[] args) {
int[] array = {1,2,3};
func1(array);
System.out.println(Arrays.toString(array));
// func2(array);
}
执行func1方法,此时输出的结果是怎样的?
我们看,array传进去之后,func1的形参array1接收到array的地址,此时两者都指向{1 , 2 , 3,}
然后array1又new了一下!此时array1又指向了新的对象 ,也就是{ 15 , 16 , 17 },所以最后的结果就是
如果运行func2方法呢? 大家有兴趣可以试一下!
总结:
1.当数组作为参数进行传递的时候,其实传的还是一个值!只不过这个值是堆上一个对象的地址!
2.使用数组作为参数进行传递,不一定改变实参的值,要看形参做了什么
第一种情况:形参修改了实参指向对象的内容
第二种情况:形参new了一个对象,这样就修改了自己的指向(本来是指向实参的)
也就是说将数组的元素每个都乘2,很简单
public static int[] grow(int[] array) {
int[] tmpArray = new int[array.length];//新定义一个数组存放2倍后的数组
for (int i = 0; i < array.length; i++) {
tmpArray[i] = array[i] * 2 ; //将原数组的每个元素*2后,放到新数组中
}
return tmpArray; //返回新数组
}
public static void main(String[] args) {
//数组元素的二倍
int[] array = {1,2,3,4,6,7,8};
int[] ret = grow(array);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(ret));
}
这里写复杂是为了理解下面的数组拷贝的只是,此时运行结果是在下面:
ps:Array.toString(这里放数组!),是将括号里面的数组元素以字符串的形式打印出来!很方便!
此时的我们可以看到,array的元素没有被改变,因为返回的是新的数组,此时就是一个深拷贝!
Arrays.copyOfRange(array, 1,3)
这个方法是左闭右开的,那下面代码举例,就是数组下标1~3的元素都拷贝走
但是其实是[ 1,3),也就是只会拷贝下标为1 和 2 的值到新数组
public static void main(String[] args) {
int[] array = {1, 2, 3, 4};
int[] ret = Arrays.copyOfRange(array, 1,3);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(ret));
System.out.println("========");
ret[0] = 999;
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(ret));
}
运行结果:
简而言之:拷贝之后,通过新数组修改值,如果原数组的值也被改变, 就是浅拷贝
拷贝之后,通过新数组修改值,如果原数组的值没有被改变,就是深拷贝
方法: Arrays.copyOf(array, array.length) 拷贝数组的一个方法,可以记一下,和上面的范围拷贝有所不同
int[] array1 = {1, 2, 3, 4}; int[] array2 = array1.clone();//另外一种方法,直接数组.clone 意思是直接拷贝原数组的副本
public static void main(String[] args) {
int[] array = {1, 2, 3, 4};
int[] ret = Arrays.copyOf(array, array.length);
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(ret));
System.out.println("========");
ret[0] = 999;
System.out.println(Arrays.toString(array));
System.out.println(Arrays.toString(ret));
}
运行结果:
ret数组就是拷贝了array数组的值,此时修改ret的值,array中的值不会发生改变,此时就是深拷贝
这里不举例代码,直接看图
此时的array1 和 array 2 的每个元素 都指向对应的对象,此时不论通过array1还是array2修改对象的值,值都会发生改变,此时叫做浅拷贝!!!
总结:我只是个初学者,写的东西难免有疏漏或者不正确,请指正!