Java方法的参数传递方式为: 值传递

Java方法的参数传递方式为: 值传递

对于基本数据类型作为参数传递时, 是"按值传递", 这点都认识很清楚. 但是, 当对象或者说引用作为参数传递, Java 的参数传递方式是"按值传递", 还是"按引用传递", 对于新接触Java的朋友来说, 可能有点难以分清. 甚至可能有些用过一段时间的朋友对此也有争议. 

首先我观点是Java参数传递方式只有一种, 就是按值传递.

先看一个代码, 如下:

public class Word {

    public Word(String word) {
        this.str = word;    
    }

    public String str;

    public String getStr() {
        return str;
    }
}
public class Tester {

    public static void main(String[] args) {
        Tester tester=new Tester();
        Word firstWord=new Word("Hello WOrld");
        System.out.println("新建对象:"+firstWord.str);
        tester.changeData(firstWord);
        System.out.println("执行changeData后,原对象的str属性值"+firstWord.str);
    }
    
    public void changeData(Word word){        
        word.str="Hello Kitty";        
        System.out.println("更改后的值:"+word.getStr());
    }
}

运行后输出为:

新建对象:Hello WOrld
changeData方法体中更改后值:Hello Kitty
执行changeData后,FirstWord对象的str属性值Hello Kitty

这里将类 firstWord 传入后, changeData 方法把 Hello World 改成了 Hello Kitty, 并且在方法体中调用 getStr方法获得确实改称了 Hello Kitty, 回到 main 函数中, 发现 firstWord 中的str 也是 Hello Kitty.

这给人感觉是把 firstWord 对象本身传给了changeData方法, 于是在方法中对word的修改后相当于是对 firstWord 的修改. 可能很多时候会想到用这个方式来  "修改"变量: 把对象作为实参传递给某个方法, 通过在方法中对形参变量的操作来改变原对像的值, 调用结束后传参的对象改变, 特别是需要有多个返回值时.  但是这样使用时要要小心了, 

因为实际二者是相互独立的, 是两个不同的变量,

如图所示,假如Hello World对象地址是 @123,两个引用变量存的是这个地址:

请看下面代码:

public class Tester {

    public static void main(String[] args) {
        Tester tester=new Tester();
        new Word("ff");
        Word firstWord=new Word("Hello WOrld");
        System.out.println("新建对象:"+firstWord.str);
        tester.changeData(firstWord);
        System.out.println("执行changeData后,FirstWord对象的str属性值"+firstWord.str);
    }
    
    public void changeData(Word word){        
        word.str="Hello Kitty";        
        System.out.println("changeData方法体中更改后值:"+word.getStr());
        word.str=null;
    }
}

我们在最后一行加了一句 : word.str=null; 输出结果:

新建对象:Hello WOrld
changeData方法体中更改后值:Hello Kitty
执行changeData后,FirstWord对象的str属性值null

从代码运行结果和上图可以看到, 把 word 置成 null 后, 并不会影响到 firstWord , firstWord 依然存在, 这就说明, 二者是独立的 两个 不同 变量.

可能你会说, 我又一般又不会在changeData 函数体内设置成 null, 上面方法还是没啥关系. 但请间下面的一个情形, 可能一不小心就会犯类似错误:

public class Tester {

    public static void main(String[] args) {
        Tester tester=new Tester();
        new Word("ff");
        Word firstWord=new Word("Hello WOrld");
        System.out.println("新建对象:"+firstWord.str);
        tester.changeData(firstWord);
        System.out.println("执行changeData后,FirstWord对象的str属性值"+firstWord.str);
    }
    
    public void changeData(Word word){        
        word= new Word("Hello Kitty");
        System.out.println("changeData方法体中更改后值:"+word.getStr());
    }
}

可能有些想法是, 把 firstWord 传给了 形参 word, 接着 把word指向一个新建的 Hello Kitty, 那么firstWord 应该也指向了 Hello Kitty.

看看程序输出结果:

新建对象:Hello WOrld
changeData方法体中更改后值:Hello Kitty
执行changeData后,FirstWord对象的str属性值Hello WOrld

发现实际并不是changeData 方法后, firstWord和word都指向 Hello Kitty, firstWord 依然指向 Hello World, 这时, 如果对Java传参了解不够, 认为传递对象进函数, 在函数内形参进行设计好的算法操作后,可以获得改变后的对象.  在这里, 就发现并不能实现这样愿望.

如果认为 Java对象作参数时,是引用传递, 当代码写长后, 可能一不小心就会出现上面类似的错误. 而且这样错误时通常还很难察觉出来.

如上面所述, 实际上对象作为参数传递时, 传递的仍然是 "值":

在mian函数中, new Word("Hello WOrld") 语句创建了 firstWord对象, 并且定义了叫 firstWord 的"引用变量" 来指向该对象(firstWord引用变量所存的是new Word("Hello WOrld") 对象的地址, 这和基本数据类型int是一样的, 只不过 int 存数值, 引用变量存地址). 传参时, 实际是把firstWord变量所存的地址值 复制了一份, 给了形参 word, 这时候他们都指向了同一个对象, 因此在 word 中更改的对象与 firstWord指向的是同一个对象, 所以这时更改会影响 firstWord. 但是word 和 firstWord 是相互独立的两个变量, 这和 C 语言中引用传递时指针的机制是不同的.

如下图所示:

原文地址:https://www.cnblogs.com/zztt/p/3417047.html