题主的例子,我们按顺序说明一下
List list = new ArrayList();
for (int i = 0; i < 10; i++) {
list.add(i);
}
开辟空间存储list此时内存方式如下
如图所示,在堆空间存放list中的数据,在栈空间保存堆的地址,通过list变量名得到一个地址,进而对这个地址空间做操作,也就是通过list变量名找到堆0x1111的空间,存放数字0~9
看一下add方法
add(list)实际内存变化如下:
如图所示,当执行add(list)方法时,list作为实际参数,将栈中存放的地址传给形参,也就是说形参也对堆空间0x1111操作,即形参添加100到堆中0x1111
因此,当add方法执行完毕,再通过list获取数据中就多了100
由此可见引用类型作为参数是引用传递,也就是地址传递。
对于基本数据类型int num 而言,如下图存储
在栈区域给num一块空间存放5
当调用addNum(num)方法时,如下图
将num的值复制给形参a,此时通过a操作的是栈中另一个区域,不会影响num的区域,所以不会影响原来的值。
由此可见基本类型作为参数是值传递
对于String是引用类型,但是它是特殊的引用类型,String的特点就是空间的值不会改变,如果重新复制,就要开辟新的空间
也就是说当append(a)被调用的第一时刻,像list一样,a中保存的地址和形参str中保存的地址是一样的,也就是都指向“A”
但是当形参str被重新赋值,则str不再执行“A”,而是执行别的空间
由此可见,由于形参str的指向发生了变化,因为实参a所指向的“A”并没有发生变化。
这也就是为什么,如果有频繁的字符串变化,通常建议使用StringBuilder
总结,在Java中当参数为基本数据类型就是值传递,当参数是引用类型就是引用传递