参考博客
数组创建及其内存分布情况
int[] arr1 = {1,2};
int[] arr2 = {3,4,5};
例子
import java.util.Arrays;
public class IntArr {
/**
* main方法执行过程中,变量arr1、arr2的值都没发生改变,都是
* a -> 0x0001
* b -> 0x0002
* 发生改变的是他们值所指向的堆区里的数组对象里的值
*/
public static void main(String[] args) {
int[] arr1 = {1,2};
int[] arr2 = {3,4,5};
swap1(arr1,arr2);
System.out.println("调用swap1后arr1的数组对象值:" + Arrays.toString(arr1));//调用swap1后arr1的数组对象值:[1, 2]
System.out.println("调用swap1后arr2的数组对象值:" + Arrays.toString(arr2));//调用swap1后arr2的数组对象值:[3, 4, 5]
swap2(arr1,arr2);
System.out.println("调用swap2后arr1的数组对象值:" + Arrays.toString(arr1));//调用swap2后arr1的数组对象值:[3, 4]
System.out.println("调用swap2后arr2的数组对象值:" + Arrays.toString(arr2));//调用swap2后arr2的数组对象值:[1, 2, 5]
}
/**
* 当方法被调用时:在栈区分别创建变量a,b;然后将实参arr1的值0x0001赋给形参a,实参arr2的值0x0002赋给形参b。
* a -> 0x0001 -> {1,2}
* b -> 0x0002 -> {3,4,5}
* 执行时
* 改变栈区变量a,b的值,不改变堆区数组对象里的值。
* 执行后
* a -> 0x0002 -> {3,4,5}
* b -> 0x0001 -> {1,2}
*/
public static void swap1(int[] a,int[] b) {
int[] temp = a;//在栈区创建变量temp,将a的值0x0001赋给temp => temp -> 0x0001 -> {1,2}
a = b;//将b的值0x0002赋给a => a -> 0x0002 -> {3,4,5}
b = temp;//将temp的值0x0001赋给b => b -> 0x0001 -> {1,2}
}
/**
* 当方法被调用时:在栈区分别创建变量a,b;然后将实参arr1的值0x0001赋给形参a,实参arr2的值0x0002赋给形参b。
* a -> 0x0001 -> {1,2}
* b -> 0x0002 -> {3,4,5}
* 执行时
* 改变堆区数组对象里的值,不改变栈区里变量的值。
* 执行后
* a -> 0x0001 -> {3,4}
* b -> 0x0002 -> {1,2,5}
*/
public static void swap2(int[] a,int[] b) {
for(int i=0;i<a.length;i++) {
int temp = a[i];//在栈区创建变量temp;第一次循环时值为a[0] = 1;第一次循环时值为a[1] = 2;
a[i] = b[i];//在堆区,改变数组对象里的值;第一次循环时值a = {3,2};第二次循环时a = {3,4};
b[i] = temp;//在堆区,改变数组对象里的值;第一次循环时值b = {1,4,5};第二次循环时a = {1,2,5};
}
}
}
总结
调用含有引用类型参数的方法时,传递给形参的值为堆区里真是存在的对象地址,形参通过该地址找到堆区里的对象,进而操纵对象里的值。无论方法里形参的值怎么变化,实参的值都不会发生改变,即外面实参的值永远都是原先对象地址。 如果在方法里对堆区的对象进行操作了,则实参通过地址获取到的对象也相应发生改变。