Java值传递与引用传递
前景
- 错误理解一:值传递和引用传递,区分的条件是传递的内容,如果是个值,就是值传递。如果是个引用,就是引用传递。
- 错误理解二: Java是引用传递。
- 错误理解三:传递的参数如果是普通类型,那就是值传递,如果是对象,那就是引用传递。
实参与形参
public static void main( String[ ] args) {
ParamTest pt = new ParamTest(); pt.sout( "Hollis");//实际参数为Hollis } public void sout( String name) {
/!形式参数为name system.out.println(name); }
实际参数是调用有参方法的时候真正传递的内容,而形式参数是用于接收实参内容的参数。
值传递与引用传递
上面提到了,当我们调用一个有参函数的时候,会把实际参数传递给形式参数。但是,在程序语言中,这个传递过程中传递的两种情况,即值传递和引用传递。我们来看下程序语言中是如何定义和区分值传递和引用传递的。
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
有了上面的概念,然后大家就可以写代码实践了,来看看Java中到底是值传递还是引用传递,于是,最简单的一段代码出来了:
public static void main( String[] args) {
ParamTest pt = new ParamTest(); int i = 10; pt.pass(i); System.out.println( "print in main , i is " +i); } public void pass(int j){
j = 20; system.out.println( "print in pass , j is " + j); }
上面的代码中,我们在pass方法中修改了参数j的值,然后分别在pass方法和main方法中打印参数的值。输出结果如下:
print in pass , j is 20 print in main , i is 10
public static void main(String[ ] args) {
ParamTest pt = new ParamTest(); User hollis = new User(); hollis.setName( "Hollis"); hollis.setGender("Male"); pt.pass(hollis); system.out.println( "print in main , user is " + hollis); } public void pass(User user) {
user.setName( "hollischuang"); System.out.println( "print in pass , user is " + user); }
同样是一个pass方法,同样是在pass方法内修改参数的值。输出结果如下:
print in pass , user is User{
name='hollischuang', gender='Male '} print in main , user is User{
name='hollischuang' , gender='Male '}
public static void main( string[] args) {
ParamTest pt = new ParamTest(); string name = "Hollis"; pt.pass(name ) ; System.out.println( "print in main , name is " + name); } public void pass(string name) {
name = "hollischuang"; system.out.println( "print in pass , name is " + name); }
上面的代码输出结果为
print in pass , name is hollischuangprint in main , name is Hollis
这又作何解释呢?同样传递了一个对象,但是原始参数的值并没有被修改,难道传递对象又变成值传递了?
Java中的值传递
上面,我们举了三个例子,表现的结果却不一样,这也是导致很多初学者,甚至很多高级程序员对于Java的传递类型有困惑的原因。其实,我想告诉大家的是,上面的概念没有错,只是代码的例子有问题。来,我再来给大家画—下概念中的重点,然后再举几个真正恰当的例子。
值传递是指在调用函数时将实际参数复制一份传递到函数中,这样在函数中如果对参数进行修改,将不会影响到实际参数。
引用传递是指在调用函数时将实际参数的地址直接传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数。
那么,我来给大家总结一下,值传递和引用传递之前的区别的重点是什么。
| 值传递 | 引用传递 | |
|---|---|---|
| 根本区别 | 会创建副本 copy | 不创建副本 |
| 所有 | 函数中无法改变原始对象 | 函数中可以改变原始对象 |
public static void main(String[ ] args){
ParamTest pt = new ParamTest(); User hollis = new User(); hollis.setName( "Hollis"); hollis.setGender("Male" ); pt.pass(hollis); system.out.println("print in main , user is " + hollis); public void pass(User user) {
user = new User(); user.setName( "hollischuang"); user.setGender( "Male"); system.out.println( "print in pass , user is " + user);
上面的代码中,我们在pass方法中,改变了user对象,输出结果如下:
print in pass , user is User{
name='hollischuang ' , gender='Male '} print in main , user is User{
name='Hollis', gender= 'Male '}
我们来画一张图,看一下整个过程中发生了什么,然后我再告诉你,为啥Java中只有值传递。



所以说,Java中其实还是值传递的,只不过对于对象参数,值的内容是对象的引用。
总结
无论是值传递还是引用传递,其实都是一种求值策略(Evaluation strategy)。在求值策略中,还有一种叫做按共享传递。其实Java中的参数传递严格意义上说应该是按共享传递。
按共享传递,是指在调用函数时,传递给函数的是实参的地址的拷贝(如果实参在栈中,则直接拷贝该值)。在函数内部对参数进行操作时,需要先拷贝的地址寻找到具体的值,再进行操作。如果该值在栈中,那么因为是直接拷贝的值,所以函数内部对参数进行操作不会对外部变量产生影响。如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝所以函数内对值的操作对外部变量是可见的。
所以函数内部对参数进行操作不会对外部变量产生影响。如果原来拷贝的是原值在堆中的地址,那么需要先根据该地址找到堆中对应的位置,再进行操作。因为传递的是地址的拷贝所以函数内对值的操作对外部变量是可见的。
//本文借鉴于知乎Holis先生
发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/232607.html原文链接:https://javaforall.net
