在C等其他语言中经常会遇到以下两种参数传递方式:
- 值传递:方法调用时,实际参数将它的值传递给形式参数,函数就收到的是原始值的副本,此时内存中存在两个相同内容,在方法中对形参执行处理操作只是改变拷贝的副本,并不会影响实际参数的值。
- 引用传递:方法调用时,实际参数的引用被传递给方法中相应的形式参数,函数接受到的是原始值的内存地址,在方法中形参和实参的内容(地址)相同,方法中对形参的处理会影响实参的值。
在Java中的参数传递方式都是值传递,当参数类型为int等基本数据类型时直接将值传递给形参;当参数为String、对象等引用类型时,实参将复制一份相同的引用地址传递给形参。注意这里是两个地址指向相同的内存地址,仍然是值传递,只不过复制的是引用;而引用传递是直接将引用传递,实参、形参共用的是一个地址。
如下所示,int值value传入changeInt()
并在函数内修改为2,但是函数外输出value值仍然是1,并未发生改变。
static void changeInt(int value) {
value = 2;
System.out.println("函数内value值为" + value);
}
public static void main(String[] args) {
int value = 1;
changeInt(value);
System.out.println("函数外value值为" + value);
}
/*输出如下:
函数内value值为2
函数外value值为1
*/
令很多人疑惑的是如下情况,当我们传递对象user给函数changeName()
并在其中修改user的name后,为什么原来的user也发生了改变?
static class User {
private String name;
public User(String name) {
this.name = name;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
static void changeName(User user) {
user.setName("Bob");
System.out.println("函数内user名字为" + user.getName());
}
public static void main(String[] args) {
User user = new User("Anna");
changeName(user);
System.out.println("函数外user名字为" + user.getName());
}
/*输出如下:
函数内user名字为Bob
函数外user名字为Bob
*/
这是由于函数内外的两个引用指向的是同一块内存地址,我们在函数内通过形参对同一块内存地址的user作了修改
如下所示,当我们把函数内形参的引用指向一块新的地址并作修改后,函数外实参的user并没有随之更改,可见形参、实参并不是共用一个相同的引用,因此不是引用传递。
static void changeName(User user) {
user = new User("Bob"); //把形参的引用指向另一块地址
System.out.println("函数内user名字为" + user.getName());
}
public static void main(String[] args) {
User user = new User("Anna");
changeName(user);
System.out.println("函数外user名字为" + user.getName());
}
/*输出为:
函数内user名字为Bob
函数外user名字为Anna
*/