为了便于理解,会将参数传递分为按值传递和按引用传递。
其实核心理解:实参和形参是两个变量,名称相同而已。如果都指向同一对象,而方法又改变了对象内容,则原值才发生变化。
形参、实参
- 形参: 定义方法使用的参数。
形参只会在方法被调用的时候,虚拟机才会分配内存单元,方法调用结束后便会释放所分配的内存单元。因此,形参只在方法内部有效。
基本数据类型作为参数传递
基本数据类型作为参数传递时都是传递值的拷贝。 指的是方法调用中,传递的是值的拷贝,无论怎么改变这个拷贝,原值是不会改变的。
也即是说实参把它的值传递给形参,对形参的改变不会影响实参的值。
1 | public class Test { |
输出结果:
1 | 调用前的i=5 |
对象作为参数传递
对象作为参数传递时,在方法内改变对象的值,有时原对象跟着改变,而有时又没有改变。就会让人对“传值”和“传引用”产生疑惑。
先看看两种情况的例子。
1 | public class Test { |
输出结果:
1 | s1=helloworld |
分析如下:
1 | //(1)s1,s2指向字符串的地址不同,假设为地址1,地址2 |
1 | //(2)调用changeStringBuffer方法 |
1 | //(3)ss1所指向字符串的值变为helloworld,调用者s1的值相应变化。 |
所以,s1的输出为helloworld,s2的输出结果为hello。
(注意,这里为了区分,s1,s2和ss1,ss2用了不同的名称,但有时候形参与实参的名字相同,其实两者变量是完全不同的,一个是main方法中的变量,一个是changeStringBuffer()中的局部变量。)
可以看出,在java中对象作为参数传递时,传递的是引用的地址,是把对象在内存中的地址拷贝了一份传给了参数。
拓展:
String是final类型,是个特殊的类,对它的一些操作符是重载的。比如:
1 | String str = "hello";//可能创建一个或者不创建对象。 |
从以上分析,现在可以更易理解下面的代码:
1 | public class Test { |
输出结果
1 | hello |
方法调用时,名称相同的实参和形参并不一样,一个是main()中的str ,指向存放”hello”的内存地址。一个是fun()中的str,str=”world”,str指向常量池中的”world”内存地址。ch[0]=’d’,对象的内容发生改变。
所以main()中str变量存放的对象内容依然是”hello”。ch从”abc”变为”dbc”。